Skip to content
Snippets Groups Projects
Select Git revision
  • c7873a89e409e7e8e22ec2a2eab3d2588b888775
  • master default protected
  • develop protected
  • bob_em_train
  • v3.3.1
  • v3.3.0
  • v3.2.0
  • v3.1.0
  • v3.0.4
  • v3.0.3
  • v3.0.2
  • v3.0.1
  • v3.0.0
  • v2.1.8
  • v2.1.7
  • v2.1.7b0
  • v2.1.6
  • v2.1.5
  • v2.1.4
  • v2.1.3
  • v2.1.2
  • v2.1.1
  • v2.1.0
  • v2.0.13
24 results

README.rst

Blame
  • __init__.py 6.49 KiB
    #!/usr/bin/env python
    # vim: set fileencoding=utf-8 :
    # Andre Anjos <andre.anjos@idiap.ch>
    # Mon 28 Jan 2013 16:40:27 CET
    
    """A custom build class for Pkg-config based extensions
    """
    
    import sys
    import platform
    from .pkgconfig import pkgconfig
    from distutils.extension import Extension as DistutilsExtension
    
    __version__ = __import__('pkg_resources').require('xbob.extension')[0].version
    
    def uniq(seq):
      """Uniqu-fy preserving order"""
    
      seen = set()
      seen_add = seen.add
      return [ x for x in seq if x not in seen and not seen_add(x)]
    
    def check_packages(packages):
      """Checks if the requirements for the given packages are satisfied.
    
      Raises a :py:class:`RuntimeError` in case requirements are not satisfied.
      This means either not finding a package if no version number is specified or
      veryfing that the package version does not match the required version by the
      builder.
    
      Package requirements can be set like this::
    
        "pkg > VERSION"
    
      In this case, the package version should be greater than the given version
      number. Comparisons are done using :py:mod:`distutils.version.LooseVersion`.
      You can use other comparators such as ``<``, ``<=``, ``>=`` or ``==``. If no
      version number is given, then we only require that the package is installed.
      """
    
      from re import split
    
      used = set()
      retval = []
    
      for requirement in uniq(packages):
    
        splitreq = split(r'\s*(?P<cmp>[<>=]+)\s*', requirement)
    
        if len(splitreq) not in (1, 3):
    
          raise RuntimeError("cannot parse requirement `%s'", requirement)
    
        p = pkgconfig(splitreq[0])
    
        if len(splitreq) == 3: # package + version number
    
          if splitreq[1] == '>':
            assert p > splitreq[2], "%s version is not > `%s'" % (p.name, splitreq[2])
          elif splitreq[1] == '>=':
            assert p >= splitreq[2], "%s version is not >= `%s'" % (p.name, splitreq[2])
          elif splitreq[1] == '<':
            assert p < splitreq[2], "%s version is not < `%s'" % (p, splitreq[2])
          elif splitreq[1] == '<=':
            assert p <= splitreq[2], "%s version is not <= `%s'" % (p, splitreq[2])
          elif splitreq[1] == '==':
            assert p <= splitreq[2], "%s version is not == `%s'" % (p, splitreq[2])
          else:
            raise RuntimeError("cannot parse requirement `%s'", requirement)
    
        retval.append(p)
    
        if p.name in used:
          raise RuntimeError("package `%s' had already been requested - cannot (currently) handle recurring requirements")
        used.add(p.name)
    
      return retval
    
    def generate_self_macros(extname, version):
      """Generates standard macros with library, module names and prefix"""
    
      s = extname.rsplit('.', 1)
    
      retval = [
          ('XBOB_EXT_MODULE_PREFIX', '"%s"' % s[0]),
          ('XBOB_EXT_MODULE_NAME', '"%s"' % s[1]),
          ]
    
      if sys.version_info[0] >= 3:
        retval.append(('XBOB_EXT_ENTRY_NAME', 'PyInit_%s' % s[1]))
      else:
        retval.append(('XBOB_EXT_ENTRY_NAME', 'init%s' % s[1]))
    
      if version: retval.append(('XBOB_EXT_MODULE_VERSION', '"%s"' % version))
    
      return retval
    
    
    class Extension(DistutilsExtension):
      """Extension building with pkg-config packages.
    
      See the documentation for :py:class:`distutils.extension.Extension` for more
      details on input parameters.
      """
    
      def __init__(self, *args, **kwargs):
        """Initialize the extension with parameters.
    
        Pkg-config extensions adds a single parameter to the standard arguments of
        the constructor:
    
        pkgconfig : [list]
    
          This should be a list of strings indicating the name of the bob
          (pkg-config) modules you would like to have linked to your extension
          **additionally** to ``bob-python``. Candidates are module names like
          "bob-machine" or "bob-math".
    
          For convenience, you can also specify "opencv" or other 'pkg-config'
          registered packages as a dependencies.
        """
    
        packages = []
    
        if 'packages' in kwargs and kwargs['packages']:
          if isinstance(kwargs['packages'], str):
            packages.append(kwargs['packages'])
          else:
            packages.extend(kwargs['packages'])
    
        if 'packages' in kwargs: del kwargs['packages']
    
        # Check all requirements
        pkgs = check_packages(packages)
    
        # Was a version parameter given?
        version = None
        if 'version' in kwargs:
          version = kwargs['version']
          del kwargs['version']
    
        # Mixing
        parameters = {
            'define_macros': generate_self_macros(args[0], version),
            'extra_compile_args': ['-std=c++0x'], #synomym for c++11?
            'library_dirs': [],
            'libraries': [],
            }
    
        # Compilation options
        if platform.system() == 'Darwin':
          parameters['extra_compile_args'] += ['-Wno-#warnings']
    
        user_includes = kwargs.get('include_dirs', [])
        pkg_includes = []
    
        for pkg in pkgs:
    
          # Adds parameters for each package, in order
          parameters['define_macros'] += pkg.package_macros()
    
          # Include directories are added with a special path
          for k in pkg.include_directories():
            if k in user_includes or k in pkg_includes: continue
            parameters['extra_compile_args'].extend(['-isystem', k])
            pkg_includes.append(k)
    
          parameters['define_macros'] += pkg.package_macros()
          parameters['library_dirs'] += pkg.library_directories()
    
          if pkg.name.find('bob-') == 0: # one of bob's packages
    
            # make-up the names of versioned Bob libraries we must link against
    
            if platform.system() == 'Darwin':
              libs = ['%s.%s' % (k, pkg.version) for k in pkg.libraries()]
            elif platform.system() == 'Linux':
              libs = [':lib%s.so.%s' % (k, pkg.version) for k in pkg.libraries()]
            else:
              raise RuntimeError("supports only MacOSX and Linux builds")
    
          else:
    
            libs = pkg.libraries()
    
          parameters['libraries'] += libs
    
        # Filter and make unique
        for key in parameters.keys():
    
          # Tune input parameters if they were set
          if key in kwargs: kwargs[key].extend(parameters[key])
          else: kwargs[key] = parameters[key]
    
          if key in ('extra_compile_args'): continue
    
          kwargs[key] = uniq(kwargs[key])
    
        # Uniq'fy parameters that are not on our parameter list
        kwargs['include_dirs'] = uniq(kwargs.get('include_dirs', []))
    
        # Make sure the language is correctly set to C++
        kwargs['language'] = 'c++'
    
        # On Linux, set the runtime path
        if platform.system() == 'Linux':
          kwargs.setdefault('runtime_library_dirs', [])
          kwargs['runtime_library_dirs'] += kwargs['library_dirs']
          kwargs['runtime_library_dirs'] = uniq(kwargs['runtime_library_dirs'])
    
        # Run the constructor for the base class
        DistutilsExtension.__init__(self, *args, **kwargs)