Example #1
0
    def build_extension_sources(self, ext):
        sources = list(ext.sources)

        log.info('building extension "%s" sources' % (ext.name))

        fullname = self.get_ext_fullname(ext.name)

        modpath = fullname.split('.')
        package = '.'.join(modpath[0:-1])

        if self.inplace:
            build_py = self.get_finalized_command('build_py')
            self.ext_target_dir = build_py.get_package_dir(package)

        sources = self.generate_sources(sources, ext)

        sources = self.template_sources(sources, ext)

        sources = self.swig_sources(sources, ext)

        sources = self.f2py_sources(sources, ext)

        sources, py_files = self.filter_py_files(sources)

        if not self.py_modules.has_key(package):
            self.py_modules[package] = []
        modules = []
        for f in py_files:
            module = os.path.splitext(os.path.basename(f))[0]
            modules.append((package, module, f))
        self.py_modules[package] += modules

        ext.sources = sources
        return
Example #2
0
 def generate_sources(self, sources, extension):
     new_sources = []
     func_sources = []
     for source in sources:
         if type(source) is type(''):
             new_sources.append(source)
         else:
             func_sources.append(source)
     if not func_sources:
         return new_sources
     if self.inplace:
         build_dir = self.ext_target_dir
     else:
         if type(extension) is type(()):
             name = extension[0]
         else:
             name = extension.name
         build_dir = os.path.join(*([self.build_src]\
                                    +name.split('.')[:-1]))
     self.mkpath(build_dir)
     for func in func_sources:
         source = func(extension, build_dir)
         if type(source) is type([]):
             [log.info("  adding '%s' to sources." % (s)) for s in source]
             new_sources.extend(source)
         else:
             log.info("  adding '%s' to sources." % (source))
             new_sources.append(source)
     return new_sources
Example #3
0
    def make_release_tree(self, base_dir, files):
        """Create the directory tree that will become the source
        distribution archive.  All directories implied by the filenames in
        'files' are created under 'base_dir', and then we hard link or copy
        (if hard linking is unavailable) those files into place.
        Essentially, this duplicates the developer's source tree, but in a
        directory named after the distribution, containing only the files
        to be distributed.
        """
        # Create all the directories under 'base_dir' necessary to
        # put 'files' there; the 'mkpath()' is just so we don't die
        # if the manifest happens to be empty.

        dest_files = remove_common_base(files)
        self.mkpath(base_dir)
        dir_util.create_tree(base_dir,
                             dest_files,
                             verbose=self.verbose,
                             dry_run=self.dry_run)

        # And walk over the list of files, either making a hard link (if
        # os.link exists) to each one that doesn't already exist in its
        # corresponding location under 'base_dir', or copying each file
        # that's out-of-date in 'base_dir'.  (Usually, all files will be
        # out-of-date, because by default we blow away 'base_dir' when
        # we're done making the distribution archives.)

        if 0 and hasattr(os, 'link'):  # can make hard links on this system
            link = 'hard'
            msg = "making hard links in %s..." % base_dir
        else:  # nope, have to copy
            link = None
            msg = "copying files to %s..." % base_dir
        self._use_hard_link = not not link

        if not files:
            log.warn("no files to distribute -- empty manifest?")
        else:
            log.info(msg)

        dest_files = [os.path.join(base_dir, file) for file in dest_files]
        file_pairs = zip(files, dest_files)
        for file, dest in file_pairs:
            if not os.path.isfile(file):
                log.warn("'%s' not a regular file -- skipping", file)
            else:
                #ej: here is the only change -- made to handle
                # absolute paths to files as well as relative
                #par,file_name = os.path.split(file)
                #dest = os.path.join(base_dir, file_name)
                # end of changes

                # old code
                #dest = os.path.join(base_dir, file)
                #end old code
                self.copy_file(file, dest, link=link)

        self.distribution.metadata.write_pkg_info(base_dir)
Example #4
0
    def build_library_sources(self, lib_name, build_info):
        sources = list(build_info.get('sources', []))

        if not sources:
            return

        log.info('building library "%s" sources' % (lib_name))

        sources = self.generate_sources(sources, (lib_name, build_info))

        build_info['sources'] = sources
        return
Example #5
0
    def backend_split(self):
        backends = self.backends.split(',')
        if len(backends) == 1:
            self.apply_backend_info(backends[0])
            return
        log.info('splitting extensions for backends: %s' % (self.backends))
        extensions = []
        for ext in self.extensions:
            name = ext.name.split('.')[-1]
            fullname = self.get_ext_fullname(ext.name)

            def func(extension,
                     src_dir,
                     name=name,
                     fullname=fullname,
                     backends=backends):
                source = os.path.join(os.path.dirname(src_dir), name + '.py')
                if newer(__file__, source):
                    f = open(source, 'w')
                    f.write(_split_ext_template \
                            % {'name':name,'fullname':fullname,
                               'backends':backends})
                    f.close()
                return [source]

            def func_init(extension, src_dir):
                source = os.path.join(src_dir, '__init__.py')
                if newer(__file__, source):
                    f = open(source, 'w')
                    f.close()
                return [source]

            for b in backends:
                new_ext = self.split_extension(ext, b)
                new_ext.sources.append(func_init)
                extensions.append(new_ext)

                new_package = dot_join(*(ext.name.split('.')[:-1] + ['_' + b]))
                new_package_dir = os.path.join(
                    *([self.build_src] + ext.name.split('.')[:-1] + ['_' + b]))
                if new_package not in self.distribution.packages:
                    self.distribution.packages.append(new_package)
                    self.distribution.package_dir[
                        new_package] = new_package_dir

            ext.sources = [func]
            extensions.append(ext)
        self.extensions[:] = extensions
        return
Example #6
0
 def apply_backend_info(self, backend):
     log.info('applying backend (%s) info to extensions'\
              % (backend))
     backend_info = get_info(backend, notfound_action=1)
     if not backend_info:
         return
     extensions = []
     for ext in self.extensions:
         ext_args = {}
         for a in _get_constructor_argnames(ext):
             ext_args[a] = copy.copy(getattr(ext, a))
         dict_append(ext_args, **backend_info)
         new_ext = Extension(**ext_args)
         extensions.append(new_ext)
     self.extensions[:] = extensions
     return
Example #7
0
 def template_sources(self, sources, extension):
     new_sources = []
     for source in sources:
         (base, ext) = os.path.splitext(source)
         if ext == '.src':  # Template file
             if self.inplace:
                 target_dir = os.path.dirname(base)
             else:
                 target_dir = appendpath(self.build_src,
                                         os.path.dirname(base))
             self.mkpath(target_dir)
             target_file = os.path.join(target_dir, os.path.basename(base))
             depends = [source] + extension.depends
             if (self.force or newer_group(depends, target_file)):
                 log.info("from_template:> %s" % (target_file))
                 outstr = process_file(source)
                 fid = open(target_file, 'w')
                 fid.write(outstr)
                 fid.close()
             new_sources.append(target_file)
         else:
             new_sources.append(source)
     return new_sources
Example #8
0
    def swig_sources(self, sources, extension):
        # Assuming SWIG 1.3.14 or later. See compatibility note in
        #   http://www.swig.org/Doc1.3/Python.html#Python_nn6

        new_sources = []
        swig_sources = []
        swig_targets = {}
        target_dirs = []
        py_files = []  # swig generated .py files
        target_ext = '.c'
        typ = None
        is_cpp = 0
        skip_swig = 0
        ext_name = extension.name.split('.')[-1]

        for source in sources:
            (base, ext) = os.path.splitext(source)
            if ext == '.i':  # SWIG interface file
                if self.inplace:
                    target_dir = os.path.dirname(base)
                    py_target_dir = self.ext_target_dir
                else:
                    target_dir = appendpath(self.build_src,
                                            os.path.dirname(base))
                    py_target_dir = target_dir
                if os.path.isfile(source):
                    name = get_swig_modulename(source)
                    assert name==ext_name[1:],'mismatch of extension names: '\
                           +source+' provides'\
                           ' '+`name`+' but expected '+`ext_name[1:]`
                    if typ is None:
                        typ = get_swig_target(source)
                        is_cpp = typ == 'c++'
                        if is_cpp:
                            target_ext = '.cpp'
                    else:
                        assert typ == get_swig_target(source), ` typ `
                    target_file = os.path.join(target_dir,'%s_wrap%s' \
                                               % (name, target_ext))
                else:
                    log.debug('  source %s does not exist: skipping swig\'ing.' \
                             % (source))
                    name = ext_name[1:]
                    skip_swig = 1
                    target_file = _find_swig_target(target_dir, name)
                    if not os.path.isfile(target_file):
                        log.debug('  target %s does not exist:\n   '\
                                  'Assuming %s_wrap.{c,cpp} was generated with '\
                                  '"build_src --inplace" command.' \
                                 % (target_file, name))
                        target_dir = os.path.dirname(base)
                        target_file = _find_swig_target(target_dir, name)
                        assert os.path.isfile(
                            target_file), ` target_file ` + ' missing'
                        log.debug('   Yes! Using %s as up-to-date target.' \
                                  % (target_file))
                target_dirs.append(target_dir)
                new_sources.append(target_file)
                py_files.append(os.path.join(py_target_dir, name + '.py'))
                swig_sources.append(source)
                swig_targets[source] = new_sources[-1]
            else:
                new_sources.append(source)

        if not swig_sources:
            return new_sources

        if skip_swig:
            return new_sources + py_files

        map(self.mkpath, target_dirs)
        swig = self.find_swig()
        swig_cmd = [swig, "-python"]
        if is_cpp:
            swig_cmd.append('-c++')
        for d in extension.include_dirs:
            swig_cmd.append('-I' + d)
        for source in swig_sources:
            target = swig_targets[source]
            depends = [source] + extension.depends
            if self.force or newer_group(depends, target, 'newer'):
                log.info("%s: %s" % (os.path.basename(swig) \
                                     + (is_cpp and '++' or ''), source))
                self.spawn(swig_cmd + self.swigflags \
                           + ["-o", target, '-outdir', py_target_dir, source])
            else:
                log.debug("  skipping '%s' swig interface (up-to-date)" \
                         % (source))

        return new_sources + py_files
Example #9
0
    def f2py_sources(self, sources, extension):
        new_sources = []
        f2py_sources = []
        f_sources = []
        f2py_targets = {}
        target_dirs = []
        ext_name = extension.name.split('.')[-1]
        skip_f2py = 0

        for source in sources:
            (base, ext) = os.path.splitext(source)
            if ext == '.pyf':  # F2PY interface file
                if self.inplace:
                    target_dir = os.path.dirname(base)
                else:
                    target_dir = appendpath(self.build_src,
                                            os.path.dirname(base))
                if os.path.isfile(source):
                    name = get_f2py_modulename(source)
                    assert name==ext_name,'mismatch of extension names: '\
                           +source+' provides'\
                           ' '+`name`+' but expected '+`ext_name`
                    target_file = os.path.join(target_dir, name + 'module.c')
                else:
                    log.debug('  source %s does not exist: skipping f2py\'ing.' \
                              % (source))
                    name = ext_name
                    skip_f2py = 1
                    target_file = os.path.join(target_dir, name + 'module.c')
                    if not os.path.isfile(target_file):
                        log.debug('  target %s does not exist:\n   '\
                                  'Assuming %smodule.c was generated with '\
                                  '"build_src --inplace" command.' \
                                  % (target_file, name))
                        target_dir = os.path.dirname(base)
                        target_file = os.path.join(target_dir,
                                                   name + 'module.c')
                        assert os.path.isfile(
                            target_file), ` target_file ` + ' missing'
                        log.debug('   Yes! Using %s as up-to-date target.' \
                                  % (target_file))
                target_dirs.append(target_dir)
                f2py_sources.append(source)
                f2py_targets[source] = target_file
                new_sources.append(target_file)
            elif fortran_ext_match(ext):
                f_sources.append(source)
            else:
                new_sources.append(source)

        if not (f2py_sources or f_sources):
            return new_sources

        map(self.mkpath, target_dirs)

        f2py_options = extension.f2py_options + self.f2pyflags
        if f2py_sources:
            assert len(f2py_sources)==1,\
                   'only one .pyf file is allowed per extension module but got'\
                   ' more:'+`f2py_sources`
            source = f2py_sources[0]
            target_file = f2py_targets[source]
            target_dir = os.path.dirname(target_file) or '.'
            depends = [source] + extension.depends
            if (self.force or newer_group(depends, target_file,'newer')) \
                   and not skip_f2py:
                log.info("f2py: %s" % (source))
                import f2py2e
                f2py2e.run_main(f2py_options +
                                ['--build-dir', target_dir, source])
            else:
                log.debug("  skipping '%s' f2py interface (up-to-date)" %
                          (source))
        else:
            #XXX TODO: --inplace support for sdist command
            if type(extension) is type(()): name = extension[0]
            else: name = extension.name
            target_dir = os.path.join(*([self.build_src]\
                                        +name.split('.')[:-1]))
            target_file = os.path.join(target_dir, ext_name + 'module.c')
            new_sources.append(target_file)
            depends = f_sources + extension.depends
            if (self.force or newer_group(depends, target_file, 'newer')) \
                   and not skip_f2py:
                import f2py2e
                log.info("f2py:> %s" % (target_file))
                self.mkpath(target_dir)
                f2py2e.run_main(f2py_options + ['--lower',
                                                '--build-dir',target_dir]+\
                                ['-m',ext_name]+f_sources)
            else:
                log.debug("  skipping f2py fortran files for '%s' (up-to-date)"\
                          % (target_file))

        assert os.path.isfile(target_file), ` target_file ` + ' missing'

        target_c = os.path.join(self.build_src, 'fortranobject.c')
        target_h = os.path.join(self.build_src, 'fortranobject.h')
        log.info("  adding '%s' to sources." % (target_c))
        new_sources.append(target_c)
        if self.build_src not in extension.include_dirs:
            log.info("  adding '%s' to include_dirs." \
                     % (self.build_src))
            extension.include_dirs.append(self.build_src)

        if not skip_f2py:
            import f2py2e
            d = os.path.dirname(f2py2e.__file__)
            source_c = os.path.join(d, 'src', 'fortranobject.c')
            source_h = os.path.join(d, 'src', 'fortranobject.h')
            if newer(source_c, target_c) or newer(source_h, target_h):
                self.mkpath(os.path.dirname(target_c))
                self.copy_file(source_c, target_c)
                self.copy_file(source_h, target_h)
        else:
            assert os.path.isfile(target_c), ` target_c ` + ' missing'
            assert os.path.isfile(target_h), ` target_h ` + ' missing'

        for name_ext in ['-f2pywrappers.f', '-f2pywrappers2.f90']:
            filename = os.path.join(target_dir, ext_name + name_ext)
            if os.path.isfile(filename):
                log.info("  adding '%s' to sources." % (filename))
                f_sources.append(filename)

        return new_sources + f_sources
Example #10
0
    def build_libraries(self, libraries):

        compiler = self.compiler
        fcompiler = self.fcompiler

        for (lib_name, build_info) in libraries:
            sources = build_info.get('sources')
            if sources is None or type(sources) not in (ListType, TupleType):
                raise DistutilsSetupError, \
                      ("in 'libraries' option (library '%s'), " +
                       "'sources' must be present and must be " +
                       "a list of source filenames") % lib_name
            sources = list(sources)

            lib_file = compiler.library_filename(lib_name,
                                                 output_dir=self.build_clib)

            depends = sources + build_info.get('depends', [])
            if not (self.force or newer_group(depends, lib_file, 'newer')):
                log.debug("skipping '%s' library (up-to-date)", lib_name)
                continue
            else:
                log.info("building '%s' library", lib_name)

            macros = build_info.get('macros')
            include_dirs = build_info.get('include_dirs')
            extra_postargs = build_info.get('extra_compiler_args') or []

            c_sources, cxx_sources, f_sources, fmodule_sources \
                       = filter_sources(sources)

            if self.compiler.compiler_type == 'msvc':
                # this hack works around the msvc compiler attributes
                # problem, msvc uses its own convention :(
                c_sources += cxx_sources
                cxx_sources = []

            if fmodule_sources:
                print 'XXX: Fortran 90 module support not implemented or tested'
                f_sources.extend(fmodule_sources)

            objects = []
            if c_sources:
                log.info("compiling C sources")
                objects = compiler.compile(c_sources,
                                           output_dir=self.build_temp,
                                           macros=macros,
                                           include_dirs=include_dirs,
                                           debug=self.debug,
                                           extra_postargs=extra_postargs)

            if cxx_sources:
                log.info("compiling C++ sources")
                old_compiler = self.compiler.compiler_so[0]
                self.compiler.compiler_so[0] = self.compiler.compiler_cxx[0]

                cxx_objects = compiler.compile(cxx_sources,
                                               output_dir=self.build_temp,
                                               macros=macros,
                                               include_dirs=include_dirs,
                                               debug=self.debug,
                                               extra_postargs=extra_postargs)
                objects.extend(cxx_objects)

                self.compiler.compiler_so[0] = old_compiler

            if f_sources:
                log.info("compiling Fortran sources")
                f_objects = fcompiler.compile(f_sources,
                                              output_dir=self.build_temp,
                                              macros=macros,
                                              include_dirs=include_dirs,
                                              debug=self.debug,
                                              extra_postargs=[])
                objects.extend(f_objects)

            self.compiler.create_static_lib(objects,
                                            lib_name,
                                            output_dir=self.build_clib,
                                            debug=self.debug)
        return
Example #11
0
    def build_extension(self, ext):
        sources = ext.sources
        if sources is None or type(sources) not in (ListType, TupleType):
            raise DistutilsSetupError, \
                  ("in 'ext_modules' option (extension '%s'), " +
                   "'sources' must be present and must be " +
                   "a list of source filenames") % ext.name
        sources = list(sources)

        if not sources:
            return

        fullname = self.get_ext_fullname(ext.name)
        if self.inplace:
            modpath = string.split(fullname, '.')
            package = string.join(modpath[0:-1], '.')
            base = modpath[-1]

            build_py = self.get_finalized_command('build_py')
            package_dir = build_py.get_package_dir(package)
            ext_filename = os.path.join(package_dir,
                                        self.get_ext_filename(base))
        else:
            ext_filename = os.path.join(self.build_lib,
                                        self.get_ext_filename(fullname))
        depends = sources + ext.depends

        if not (self.force or newer_group(depends, ext_filename, 'newer')):
            log.debug("skipping '%s' extension (up-to-date)", ext.name)
            return
        else:
            log.info("building '%s' extension", ext.name)

        extra_args = ext.extra_compile_args or []
        macros = ext.define_macros[:]
        for undef in ext.undef_macros:
            macros.append((undef, ))

        c_sources, cxx_sources, f_sources, fmodule_sources = \
                   filter_sources(ext.sources)
        if self.compiler.compiler_type == 'msvc':
            if cxx_sources:
                # Needed to compile kiva.agg._agg extension.
                extra_args.append('/Zm1000')
            # this hack works around the msvc compiler attributes
            # problem, msvc uses its own convention :(
            c_sources += cxx_sources
            cxx_sources = []

        if sys.version[:3] >= '2.3':
            kws = {'depends': ext.depends}
        else:
            kws = {}

        backend = getattr(ext, 'backend', None)
        if backend is not None:
            output_dir = os.path.join(self.build_temp, '_' + backend)
        else:
            output_dir = self.build_temp

        c_objects = []
        if c_sources:
            log.info("compiling C sources")
            c_objects = self.compiler.compile(c_sources,
                                              output_dir=output_dir,
                                              macros=macros,
                                              include_dirs=ext.include_dirs,
                                              debug=self.debug,
                                              extra_postargs=extra_args,
                                              **kws)
        if cxx_sources:
            log.info("compiling C++ sources")

            old_compiler = self.compiler.compiler_so[0]
            self.compiler.compiler_so[0] = self.compiler.compiler_cxx[0]

            c_objects += self.compiler.compile(cxx_sources,
                                               output_dir=output_dir,
                                               macros=macros,
                                               include_dirs=ext.include_dirs,
                                               debug=self.debug,
                                               extra_postargs=extra_args,
                                               **kws)
            self.compiler.compiler_so[0] = old_compiler

        check_for_f90_modules = not not fmodule_sources

        if f_sources or fmodule_sources:
            extra_postargs = []
            include_dirs = ext.include_dirs[:]
            module_dirs = ext.module_dirs[:]

            #if self.fcompiler.compiler_type=='ibm':
            macros = []

            if check_for_f90_modules:
                module_build_dir = os.path.join(\
                    self.build_temp,os.path.dirname(\
                    self.get_ext_filename(fullname)))

                self.mkpath(module_build_dir)
                if self.fcompiler.module_dir_switch is None:
                    existing_modules = glob('*.mod')
                extra_postargs += self.fcompiler.module_options(\
                    module_dirs,module_build_dir)

            f_objects = []
            if fmodule_sources:
                log.info("compiling Fortran 90 module sources")
                f_objects = self.fcompiler.compile(
                    fmodule_sources,
                    output_dir=self.build_temp,
                    macros=macros,
                    include_dirs=include_dirs,
                    debug=self.debug,
                    extra_postargs=extra_postargs,
                    depends=ext.depends)

            if check_for_f90_modules \
                   and self.fcompiler.module_dir_switch is None:
                for f in glob('*.mod'):
                    if f in existing_modules:
                        continue
                    try:
                        self.move_file(f, module_build_dir)
                    except DistutilsFileError:  # already exists in destination
                        os.remove(f)

            if f_sources:
                log.info("compiling Fortran sources")
                f_objects += self.fcompiler.compile(
                    f_sources,
                    output_dir=self.build_temp,
                    macros=macros,
                    include_dirs=include_dirs,
                    debug=self.debug,
                    extra_postargs=extra_postargs,
                    depends=ext.depends)
        else:
            f_objects = []

        objects = c_objects + f_objects

        if ext.extra_objects:
            objects.extend(ext.extra_objects)
        extra_args = ext.extra_link_args or []

        try:
            old_linker_so_0 = self.compiler.linker_so[0]
        except:
            pass

        use_fortran_linker = getattr(ext, 'language', 'c') in ['f77', 'f90']
        c_libraries = []
        c_library_dirs = []
        if use_fortran_linker or f_sources:
            use_fortran_linker = 1
        elif self.distribution.has_c_libraries():
            build_clib = self.get_finalized_command('build_clib')
            f_libs = []
            for (lib_name, build_info) in build_clib.libraries:
                if has_f_sources(build_info.get('sources', [])):
                    f_libs.append(lib_name)
                if lib_name in ext.libraries:
                    # XXX: how to determine if c_libraries contain
                    # fortran compiled sources?
                    c_libraries.extend(build_info.get('libraries', []))
                    c_library_dirs.extend(build_info.get('library_dirs', []))
            for l in ext.libraries:
                if l in f_libs:
                    use_fortran_linker = 1
                    break

        # Always use system linker when using MSVC compiler.
        if self.compiler.compiler_type == 'msvc' and use_fortran_linker:
            c_libraries.extend(self.fcompiler.libraries)
            c_library_dirs.extend(self.fcompiler.library_dirs)
            use_fortran_linker = 0

        if use_fortran_linker:
            if cxx_sources:
                # XXX: Which linker should be used, Fortran or C++?
                log.warn('mixing Fortran and C++ is untested')
            link = self.fcompiler.link_shared_object
            language = ext.language or self.fcompiler.detect_language(
                f_sources)
        else:
            link = self.compiler.link_shared_object
            if sys.version[:3] >= '2.3':
                language = ext.language or self.compiler.detect_language(
                    sources)
            else:
                language = ext.language
            if cxx_sources:
                self.compiler.linker_so[0] = self.compiler.compiler_cxx[0]

        if sys.version[:3] >= '2.3':
            kws = {'target_lang': language}
        else:
            kws = {}

        link(objects,
             ext_filename,
             libraries=self.get_libraries(ext) + c_libraries,
             library_dirs=ext.library_dirs + c_library_dirs,
             runtime_library_dirs=ext.runtime_library_dirs,
             extra_postargs=extra_args,
             export_symbols=self.get_export_symbols(ext),
             debug=self.debug,
             build_temp=self.build_temp,
             **kws)

        try:
            self.compiler.linker_so[0] = old_linker_so_0
        except:
            pass

        return