Example #1
0
 def _load_dependencies(self, dependencies, recurse):
     # Search for and load all packages listed in dependencies,
     # attempting to recursively load all their required packages
     # and checking for conflicts as well.
     # For d in deps:
     for dep in dependencies:
         # 0. Check if this package is already loaded
         if self._get_loaded_package(dep.name):
             continue
     # 1. Search for a package matching the spec
         pkg = self.searcher.search_for_package(dep, self.globals)
         # 2. Check for conflicts
         for conflict in pkg.properties['conflicts']:
             try:
                 ErrorPrinter().debug_print('Searching for conflict %s',
                                            conflict.name)
                 self.searcher.search_for_package(conflict)
             except PackageNotFoundError:
                 # If the conflict was not found, move on to the next
                 ErrorPrinter().debug_print('Conflict not found.')
                 continue
             # Conflict was found - what to do?
             raise PackageConflictError(pkg.name, conflict)
     # 3. Sanity check this package
         pkg.sanity_check()
         # 4. Add this package to the dictionary now to avoid infinite recursion
         self._add_package(dep.name, pkg)
         # 5. Recursively load requireds
         if recurse:
             # requires.private includes requires
             self._load_dependencies(pkg.properties['requires.private'],
                                     recurse)
Example #2
0
    def search_for_pcfile(self, pkgname):
        """Search for one or more pkg-config files matching the given
        package name. If a matching pkg-config file cannot be found,
        an empty list will be returned.

        The dictionary of known packages is stored in _known_pkgs and is
        initialised by calling init_search_dirs().

        """
        ErrorPrinter().debug_print('Looking for files matching %s', (pkgname))
        if Options().get_option('prefer_uninstalled'):
            if pkgname + '-uninstalled' in self._known_pkgs:
                # Prefer uninstalled version of a package
                ErrorPrinter().debug_print(
                    'Using uninstalled package %s',
                    (self._known_pkgs[pkgname + '-uninstalled']))
                return self._known_pkgs[pkgname + '-uninstalled']
            elif Options().get_option('uninstalled_only'):
                ErrorPrinter().debug_print(
                    'Uninstalled only, no suitable package.')
                return []
        if pkgname in self._known_pkgs:
            ErrorPrinter().debug_print('Using any package: %s',
                                       (self._known_pkgs[pkgname]))
            return self._known_pkgs[pkgname]
        else:
            ErrorPrinter().debug_print('No suitable package found')
            return []
Example #3
0
    def _init_search_dirs(self):
        # Append dirs in PKG_CONFIG_PATH
        if "config_path" in self.globals and self.globals["config_path"]:
            for d in self.globals["config_path"]:
                if not d or not isdir(d):
                    continue
                self._append_packages(d)
        # Append dirs in PKG_CONFIG_LIBDIR
        if "config_libdir" in self.globals and self.globals["config_libdir"]:
            for d in self.globals["config_libdir"]:
                if not d or not isdir(d):
                    continue
                self._append_packages(d)
        if sys.platform == 'win32':
            key_path = 'Software\\pkg-config\\PKG_CONFIG_PATH'
            for root in ((_winreg.HKEY_CURRENT_USER, 'HKEY_CURRENT_USER'),
                         (_winreg.HKEY_LOCAL_MACHINE, 'HKEY_LOCAL_MACHINE')):
                try:
                    key = _winreg.OpenKey(root[0], key_path)
                except WindowsError as e:
                    ErrorPrinter().debug_print('Failed to add paths from \
{0}\\{1}: {2}'.format(root[1], key_path, e))
                    continue
                try:
                    num_subkeys, num_vals, modified = _winreg.QueryInfoKey(key)
                    for ii in range(num_vals):
                        name, val, type = _winreg.EnumValue(key, ii)
                        if type == _winreg.REG_SZ and isdir(val):
                            self._append_packages(val)
                except WindowsError as e:
                    ErrorPrinter().debug_print('Failed to add paths from \
{0}\\{1}: {2}'.format(root[1], key_path, e))
                finally:
                    _winreg.CloseKey(key)
        # Default path: If a hard-coded path has been set, use that (excluding
        # paths that don't exist)
        if "prefix" in self.globals:
            prefix = self.globals["prefix"]
        else:
            prefix = sys.prefix
        if pc_path:
            for d in pc_path.split(self._split_char()):
                if d and isdir(d):
                    self._append_packages(d)
        # Default path: Else append prefix/lib/pkgconfig, prefix/share/pkgconfig
        else:
            if Options().get_option('is_64bit'):
                suffix = '64'
            else:
                suffix = ''
            dirs2check = (join(prefix, 'lib' + suffix),
                          join(prefix, 'lib', str(thisArchTriple)),
                          join(prefix, 'share'), join(prefix, "lib"))
            for d in dirs2check:
                d = join(d, "pkgconfig")
                if isdir(d):
                    self._append_packages(d)
Example #4
0
 def _can_open_file(self, filename):
     try:
         result = open(filename, 'r')
     except IOError as e:
         ErrorPrinter().debug_print('Could not open {0}'.format(filename))
         search_string = Options().get_option('search_string').split()
         if (not search_string and \
                 Options().get_option('command') == 'list-all') or \
                 True in [p.startswith(split(filename)[-1].split('.')[0]) \
                             for p in search_string]:
             ErrorPrinter().verbose_error(
                 "Failed to open '{0}': {1}".format(filename, e.strerror))
         return False
     return True
Example #5
0
def read_pc_file(filename, global_variables):
    """Read and parse it into two dictionaries (variables and properties).

    Returns variables and properties.

    """
    ErrorPrinter().set_variable('filename', filename)
    ErrorPrinter().debug_print('Parsing %(filename)')
    pcfile = open(filename, 'r')
    lines = pcfile.readlines()
    if not lines:
        raise EmptyPackageFileError(filename)
    raw_vars, vars, props = parse_pc_file_lines(lines, global_variables)
    pcfile.close()
    return raw_vars, vars, props
Example #6
0
 def __init__(self, version_string=None):
     if version_string is not None:
         self._parse_version(version_string)
         ErrorPrinter().debug_print('Parsed %s into %s',
                                    (version_string, self.comps))
     else:
         self.raw_string = '0'
         self.comps = [0]
Example #7
0
 def _append_packages(self, d):
     ErrorPrinter().debug_print('Adding .pc files from %s to known packages',
                                (d))
     files = listdir(d)
     for filename in files:
         if filename.endswith('.pc'):
             # Test if the file can be opened (pkg-config glosses over,
             # e.g. links that are now dead, as if they were never there).
             full_path = join(d, filename)
             name = filename[:-3]
             if name in self._known_pkgs:
                 if full_path not in self._known_pkgs[name]:
                     self._known_pkgs[name].append(full_path)
                     ErrorPrinter().debug_print('Package %s has a duplicate file: %s',
                                                (name, self._known_pkgs[name]))
             else:
                 self._known_pkgs[name] = [full_path]
Example #8
0
    def search_for_package(self, dep, globals):
        """Search for a package matching the given dependency specification
        (name and version restriction). Raise PackageNotFoundError if no
        matching package is found.

        Returns a parsed package object.

        """
        # Get a list of pc files matching the package name
        if isfile(dep.name) and splitext(dep.name)[1] == '.pc':
            # No need to search for a pc file
            ErrorPrinter().debug_print('Using provided pc file %s', (dep.name))
            pcfiles = [dep.name]
        else:
            ErrorPrinter().debug_print('Searching for package matching %s',
                                       (dep))
            pcfiles = self.search_for_pcfile(dep.name)
        ErrorPrinter().debug_print('Found .pc files: %s', (str(pcfiles)))
        if not pcfiles:
            raise PackageNotFoundError(str(dep))
        # Filter the list by those files that meet the version specification
        pkgs = []
        for pcfile in pcfiles:
            try:
                pkgs.append(Package(pcfile, globals))
            except IOError as e:
                ErrorPrinter().verbose_error("Failed to open '{0}': \
{1}".format(pcfile, e.strerror))
                continue
            except UndefinedVarError as e:
                raise UndefinedVarError(e.variable, pcfile)
        if not pkgs and pcfiles:
            # Raise an error indicating that all pc files we could try were
            # unopenable. This is necessary to match pkg-config's odd lack of
            # the standard "Package not found" error when a bad file is
            # encountred.
            raise NoOpenableFilesError(str(dep))
        pkgs = [pkg for pkg in pkgs \
                if dep.meets_requirement(pkg.properties['version'])]
        ErrorPrinter().debug_print('Filtered to %s',
                                   ([pkg.properties['name'] for pkg in pkgs]))
        if not pkgs:
            raise PackageNotFoundError(str(dep))
        return pkgs[0]
Example #9
0
def parse_line(line, raw_vars, vars, props, seen_props, globals):
    # Parse a single line from the file, adding its value to the props or vars
    # dictionary as appropriate.
    if not line:
        return raw_vars, vars, props, seen_props
    key, value, type = split_pc_file_line(line)
    # Check first if it's one of the known keys.
    if type == VARIABLE:
        # Perform substitution using variables found so far and global
        # variables, then store the result.
        if key in vars:
            raise MultiplyDefinedValueError(key)
        if key in globals:
            ErrorPrinter().debug_print('Adding %s -> %s to vars from globals',
                                       (key, value))
            raw_vars[key] = value.strip ()
            vars[key] = substitute (globals[key], vars, globals)
        else:
            ErrorPrinter().debug_print('Adding %s -> %s to vars', (key, value))
            raw_vars[key] = value.strip ()
            vars[key] = substitute (value.strip(), vars, globals)
    elif type == PROPERTY:
        if key in seen_props:
            raise MultiplyDefinedValueError(key)
        if key.lower() in empty_raw_props:
            if value is None:
                value = empty_raw_props[key.lower()]
            ErrorPrinter().debug_print('Adding %s -> %s to props', (key, value))
            props[key.lower ()] = value
            seen_props.append(key)
        else:
            # As per the original pkg-config, don't raise errors on unknown
            # keys because they may be from future additions to the file
            # format. But log an error
            ErrorPrinter().debug_print('Unknown key/value in %(filename)s:\n%s: %s',
                                       (key, value))
    else:
        # Probably a malformed line. Ignore it.
        pass
    return raw_vars, vars, props, seen_props
Example #10
0
    def _process_props(self, global_variables):
        # Processing of file data
        props = self.raw_props

        # May need to reset the prefix variable
        if sys.platform == 'win32' and \
                not Options().get_option('dont_define_prefix'):
            # Use the location of the .pc file to guess a suitable value for
            # the prefix variable. Start by checking if the absolute .pc
            # location ends with '\lib\pkgconfig'.
            abs_loc = dirname(abspath(self.filename))
            if Options().get_option('normalise_paths'):
                abs_loc = normpath(abs_loc)
            else:
                # If not normalising paths, then all paths should be in /
                # format for consistency
                abs_loc = abs_loc.replace('\\', '/')
            if abs_loc.endswith('\\lib\\pkgconfig'):
                self.variables[Options().get_option('prefix_variable')] = \
                        abs_loc.rstrip('\\lib\\pkgconfig')
                ErrorPrinter().debug_print('Replaced {0} with \
{1}'.format(Options().get_option('prefix_variable'),
                self.variables[Options().get_option('prefix_variable')]))

        # Perform substitutions
        for key in props:
            props[key] = substitute(props[key], self.variables,
                                    global_variables)

        # Parse the data
        self.properties = deepcopy(empty_processed_props)
        self.properties['name'] = props['name']
        if props['description']:
            self.properties['description'] = props['description']
        if props['version']:
            try:
                self.properties['version'] = Version(props['version'])
            except BadVersionFormatError as e:
                raise BadVersionFormatError(e.versionstring, props['name'])
        self.properties['requires'] = \
                parse_package_spec_list(props['requires'])
        self.properties['requires.private'] = \
            parse_package_spec_list(props['requires.private']) + \
            self.properties['requires']
        self.properties['conflicts'] = \
                parse_package_spec_list(props['conflicts'])
        self._parse_cflags(props['cflags'], global_variables)
        self._parse_libs(props['libs'], global_variables)
        self._parse_libs(props['libs.private'],
                         global_variables,
                         dest='private.')
Example #11
0
def split_pc_file_line(line):
    # Split a line into key and value, and determine if it is a property or a
    # variable.
    m = property_re.match(line)
    if m is not None:
        return m.group('key'), m.group('value'), PROPERTY

    m = variable_re.match(line)
    if m is not None:
        if m.group('value') is None:
            return m.group('var'), '', VARIABLE
        else:
            return m.group('var'), m.group('value'), VARIABLE

    # Gloss over malformed lines (that's what pkg-config does).
    ErrorPrinter().debug_print('Malformed line: {0}'.format(line))
    return None, None, None
Example #12
0
    def known_packages_list(self):
        """Return a list of all packages found on the system, giving a name and
        a description (from the .pc file) for each, and also a list of any
        errors encountered.

        """
        result = []
        errors = []
        for pkgname in self._known_pkgs:
            # Use the highest-priority version of the package
            try:
                pkg = Package(self._known_pkgs[pkgname][0])
            except IOError as e:
                ErrorPrinter().verbose_error("Failed to open '{0}': \
{1}".format(self._known_pkgs[pkgname][0], e.strerror))
                continue
            except UndefinedVarError as e:
                errors.append("Variable '{0}' not defined in '{1}'".format(e,
                    self._known_pkgs[pkgname][0]))
                continue
            result.append((pkgname, pkg.properties['name'], pkg.properties['description']))
        return result, errors
Example #13
0
 def _add_package(self, name, newpkg):
     ErrorPrinter().debug_print('Adding %s to list of packages as %s',
                                (newpkg.filename, name))
     self.packages.append((name, newpkg))
Example #14
0
def main(argv):
    parser = setup_option_parser()
    try:
        options, args = parser.parse_args()
    except OptionError as e:
        print('OptionError: ' + str (e))
        sys.exit(1)

    if options.realversion:
        print('{0} (Equivalent to {1}'.format(PYKG_CONFIG_VERSION,
                                              CORRESPONDING_VERSION))
        sys.exit(0)

    global_variables = {}

    zip_name = 'python{0}{1}.zip'.format(sys.version_info[0],
                                          sys.version_info[1])
    for path in sys.path:
        if path.endswith('64/' + zip_name):
            Options().set_option('is_64bit', True)
            break

    if getenv('PKG_CONFIG_SYSROOT_DIR'):
        global_variables['pc_sysrootdir'] = getenv('PKG_CONFIG_SYSROOT_DIR')
    if getenv('PKG_CONFIG_TOP_BUILD_DIR'):
        global_variables['pc_topbuilddir'] = getenv('PKG_CONFIG_TOP_BUILD_DIR')
    if getenv('PKG_CONFIG_DISABLE_UNINSTALLED'):
        Options().set_option('prefer_uninstalled', False)
    if getenv('PKG_CONFIG_ALLOW_SYSTEM_LIBS'):
        Options().set_option('forbidden_libdirs', [])
    else:
        if Options().get_option('is_64bit'):
            Options().set_option('forbidden_libdirs', ['/usr/lib64'])
        else:
            Options().set_option('forbidden_libdirs', ['/usr/lib'])
    if getenv('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS'):
        Options().set_option('forbidden_cflags', [])
    else:
        forbidden = []
        if sys.platform != 'win32':
            forbidden.append('/usr/include')
        if getenv('C_INCLUDE_PATH'):
            forbidden.append(getenv('C_INCLUDE_PATH'))
        if getenv('CPLUS_INCLUDE_PATH'):
            forbidden.append(getenv('CPLUS_INCLUDE_PATH'))
        Options().set_option('forbidden_cflags', forbidden)

    if options.full_compatibility:
        Options().set_option('full_compatibility', True)
    else:
        Options().set_option('full_compatibility', False)

    if options.atleast_pkgconfig_version:
        other_version = Version(options.atleast_pkgconfig_version)
        if other_version > get_pkg_config_version():
            sys.exit(1)
        else:
            sys.exit(0)
    if options.static:
        Options().set_option('private_libs', True)
    if options.short_errors:
        Options().set_option('short_errors', True)
    if options.define_variable:
        for var_def in options.define_variable:
            sub_strings = var_def.split('=')
            if len(sub_strings) != 2:
                print('Bad argument format for define-variable: {1}'.format(var_def))
                sys.exit(1)
            global_variables[sub_strings[0]] = sub_strings[1]
    if options.debug:
        Options().set_option('debug', True)
    if options.errors_to_stdout:
        Options().set_option('error_dest', sys.stdout)
    if sys.platform == 'win32':
        if options.dont_define_prefix:
            Options().set_option('dont_define_prefix', True)
        else:
            Options().set_option('dont_define_prefix', False)
        if options.prefix_variable:
            Options().set_option('prefix_variable', options.prefix_variable)
        if options.msvc_syntax:
            Options().set_option('use_msvc_syntax', True)
        else:
            Options().set_option('use_msvc_syntax', False)
    if options.normalise_paths:
        Options().set_option('normalise_paths', True)
    else:
        Options().set_option('normalise_paths', False)

    if options.modversion or options.libs or options.libs_only_l or \
            options.libs_only_big_l or options.libs_only_other or \
            options.cflags or options.cflags_only_big_i or \
            options.cflags_only_other or options.list_all:
        if options.silence_errors:
            Options().set_option('print_errors', False)
        else:
            Options().set_option('print_errors', True)
    else:
        if options.print_errors:
            Options().set_option('print_errors', True)
        else:
            Options().set_option('print_errors', False)

    if options.list_all:
        Options().set_option('command', 'list-all')
        try:
            result = PkgCfgResult(global_variables)
            all_packages, errors = result.known_packages_list()
        except:
            ErrorPrinter().error('Exception searching for packages:')
            traceback.print_exc()
            sys.exit(1)
        if all_packages:
            max_width = max([(len(p), p) for p, n, d in all_packages])
            for package, name, description in all_packages:
                print('{0:{3}}{1} - {2}'.format(package, name, description, max_width[0] + 1))
        for e in errors:
            ErrorPrinter().error(e)
        sys.exit(0)

    try:
        Options().set_option('command', 'search')
        search = ' '.join(args)
        Options().set_option('search_string', search)
        result = PkgCfgResult(global_variables)
        result.find_packages(search, True)
    except NoOpenableFilesError as e:
        ErrorPrinter().verbose_error(str(e))
        sys.exit(1)
    except PackageNotFoundError as e:
        if not Options().get_option('short_errors'):
            ErrorPrinter().verbose_error('''Package {0} was not found in the \
pkg-config search path.
Perhaps you should add the directory containing `{0}.pc'
to the PKG_CONFIG_PATH environment variable'''.format(e.pkgname))
        ErrorPrinter().verbose_error(str(e))
        sys.exit(1)
    except NoPackagesSpecifiedError:
        Options().get_option('error_dest').write(
            'Must specify package names on the command line\n')
        sys.exit(1)
    except UndefinedVarError as e:
        ErrorPrinter().error("Variable '{0}' not defined in '{1}'".format(
            e.variable, e.pkgfile))
        sys.exit(1)
    except:
        print('Exception searching for packages')
        traceback.print_exc()
        sys.exit(1)

    if options.dump_package:
        result.dump_package()
        sys.exit(0)

    if options.exists:
        # Even if the packages don't meet the requirements, they exist, which
        # is good enough for the exists option.
        sys.exit(0)
    if options.uninstalled:
        # Check if any packages loaded (both searched-for and dependencies)
        # are uninstalled.
        if result.have_uninstalled():
            sys.exit(0)
        sys.exit(1)

    if options.modversion:
        for l in result.get_searched_pkgs_versions():
            print(l)
    found_version = \
        result.get_package_version(result.get_searched_pkg_list()[0].name)
    if options.atleast_version:
        if found_version < Version(options.atleast_version):
            sys.exit(1)
        sys.exit(0)
    if options.exact_version:
        if found_version != Version(options.exact_version):
            sys.exit(1)
        sys.exit(0)
    if options.max_version:
        if found_version > Version(options.max_version):
            sys.exit(1)
        sys.exit(0)

    if options.variable:
        value = result.get_variable_value(options.variable)
        if value == None:
            print('')
        else:
            print(value)
    if options.cflags_only_big_i:
        print(result.get_big_i_flags())
    if options.cflags_only_other:
        print(result.get_other_i_flags())
    if options.cflags:
        print(result.get_cflags())
    if options.libs_only_l:
        print(result.get_l_flags())
    if options.libs_only_big_l:
        print(result.get_big_l_flags())
    if options.libs_only_other:
        print(result.get_other_l_flags())
    if options.libs:
        print(result.get_all_lib_flags())