BuildExt.py :  » XML » 4Suite » 4Suite-XML-1.0.2 » Ft » Lib » DistExt » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » XML » 4Suite 
4Suite » 4Suite XML 1.0.2 » Ft » Lib » DistExt » BuildExt.py
import os
import re
import sys
from distutils import util,sysconfig
from distutils.command import build_ext
from distutils.dep_util import newer_group,newer
from distutils.version import StrictVersion

from Ft.Lib import ImportUtil
from Ft.Lib.DistExt import Util

# Constants for symbol stripping
STRIP_NONE = 0
STRIP_VERSIONING = 1
STRIP_EXPORTS_FILE = 2
STRIP_EXPORTS_ARGLIST = 3
STRIP_EXPORTS_POST_LINK = 4

BISONGEN_MINIMUM_VERSION = StrictVersion('0.8.0')

try:
    enumerate
except NameError:
    enumerate = lambda sequence: zip(range(len(sequence)), sequence)

class BuildExt(build_ext.build_ext):

    command_name = 'build_ext'

    def initialize_options(self):
        build_ext.build_ext.initialize_options(self)

        # How to format C symbol name to exported symbol name
        self.export_symbol_format = '%s'

        self.symbol_stripping = STRIP_NONE
        self.strip_command = None
        return

    def finalize_options(self):
        build_ext.build_ext.finalize_options(self)

        # Verify that extensions are built with the proper flags.
        # For Windows, Py_DEBUG is enabled whenever debugging information
        # is included. For other platforms, it must be explicited defined.
        if sys.platform == 'win32':
            py_debug = self.debug
        else:
            # 'getobjects()' is only available in debug builds.
            py_debug = hasattr(sys, 'getobjects')
        if py_debug and not Util.GetConfigVars('Py_DEBUG')[0]:
            macros = [('Py_DEBUG', None)]
            if not self.define:
                self.define = macros
            else:
                self.define.extend(macros)

        # If built as shared, remove the library dir if the shared library
        # is not installed there (which Python does not do by default).
        # This fixes the errors building on openSUSE 10.2 w/Python 2.5.
        if (sys.platform.startswith('linux') and
            sysconfig.get_config_var('Py_ENABLE_SHARED')):
            libpl, ldlibrary = sysconfig.get_config_vars('LIBPL', 'LDLIBRARY')
            if libpl in self.library_dirs:
                if not os.path.exists(os.path.join(libpl, ldlibrary)):
                    self.library_dirs.remove(libpl)

        # OpenBSD and NetBSD dlsyms have a leading underscore if the object
        # format is not ELF.  (from src/Python/dynload_shlib.c).
        if (sys.platform.startswith('openbsd')
            or sys.platform.startswith('netbsd')):
            # Capture predefined preprocessor macros (from src/configure)
            cc = sysconfig.get_config_var('CC')
            defines = os.popen(cc + ' -dM -E - </dev/null').read()
            # Check for ELF object format
            if defines.find('__ELF__') == -1:
                self.export_symbol_format = '_%s'

        # By limiting exported symbols, we don't need to worry about symbol
        # conflicts between the shared modules or Python itself.
        if os.name == 'nt' or sys.platform.startswith('cygwin'):
            # The compiler default is to limit exported symbols
            self.symbol_stripping = STRIP_NONE

        elif (sys.platform.startswith('linux')
              or sys.platform.startswith('freebsd')
              or sys.platform.startswith('openbsd')
              or sys.platform.startswith('netbsd')):
            # This assumes the the GNU linker is being used.
            # As of Dec 2005, the SourceForge Compile Farm servers use GNU ld
            # for OpenBSD and NetBSD.
            self.symbol_stripping = STRIP_VERSIONING
            self.strip_command = '-Wl,--version-script,%s'

        elif sys.platform.startswith('sunos'):
            self.symbol_stripping = STRIP_VERSIONING
            self.strip_command = '-Wl,-M,%s'

        elif sys.platform.startswith('darwin'):
            # Mac OS X/Darwin
            ld = sysconfig.get_config_var('LDSHARED')
            output = os.popen(ld + ' -Wl,-exported_symbols_list').read()
            if re.search('unknown flag: -exported_symbols_list', output):
                # Older OSX (10.1 or 10.2 with DevTools prior to Dec 2002)
                # Use external program (nmedit) to limit exported symbols
                self.symbol_stripping = STRIP_EXPORTS_POST_LINK
                self.strip_command = 'nmedit -s %(exports)s -p %(extension)s'
            else:
                self.symbol_stripping = STRIP_EXPORTS_FILE
                self.strip_command = '-Wl,-exported_symbols_list,%s'
                self.export_symbol_format = '_%s'

        elif sys.platform.startswith('hp-ux'):
            # HP-UX linker lists exported symbols one at a time in the
            # argument list.
            self.symbol_stripping = STRIP_EXPORTS_ARGLIST
            self.strip_command = '-Wl,+e,%s'

        elif os.name == 'posix':
            # From online manual pages, most UNIX support limiting exported
            # symbols with the same option.
            self.symbol_stripping = STRIP_EXPORTS_FILE
            self.strip_command = '-Wl,-exports_file,%s'
        return

    def check_extensions_list(self, extensions):
        build_ext.build_ext.check_extensions_list(self, extensions)

        # Add the included files for each source file
        for ext in extensions:
            if not isinstance(ext.sources, (tuple, list)):
                raise DistutilsSetupError(
                    "in 'ext_modules' option (extension '%s'), "
                    "'sources' must be present and must be "
                    "a list of source filenames" % ext.name)
            if not hasattr(ext, 'depends'):
                ext.depends = []
            if not hasattr(ext, 'includes'):
                ext.includes = {}
                for source in ext.sources:
                    includes = Util.FindIncludes(util.convert_path(source),
                                                 ext.include_dirs)
                    ext.includes[source] = includes
        return

    def get_source_files(self):
        self.check_extensions_list(self.extensions)

        filenames = []
        for extension in self.extensions:
            for source in self.prepare_sources(extension):
                filenames.append(source)
                filenames.extend(extension.includes[source])
        return filenames

    def build_extension(self, ext):
        # First, scan the sources for SWIG definition files (.i), run
        # SWIG on 'em to create .c files, and modify the sources list
        # accordingly.
        sources = self.prepare_sources(ext)

        fullname = self.get_ext_fullname(ext.name)
        ext_filename = os.path.join(self.build_lib,
                                    self.get_ext_filename(fullname))

        # Changes to the command indicate that compilation options may have
        # changed so rebuild/link everything
        command_mtime = ImportUtil.GetLastModified(__name__)
        try:
            force = command_mtime > os.stat(ext_filename).st_mtime
        except OSError:
            force = True
        force = self.force or force

        depends = sources + ext.depends
        for includes in ext.includes.values():
            depends.extend(includes)
        if not (force or newer_group(depends, ext_filename, 'newer')):
            self.announce("skipping '%s' extension (up-to-date)" % ext.name)
            return

        self.announce("building '%s' extension" % ext.name, 2)

        # Next, compile the source code to object files.
        extra_args = ext.extra_compile_args or []

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

        # Get the resulting object filenames as we are compiling the sources
        # one at a time to reduce compile time for large source lists.
        objects = self.compiler.object_filenames(sources,
                                                 sysconfig.python_build,
                                                 self.build_temp)

        self.compiler.force = force
        if sys.version >= '2.3':
            # Python 2.3 added dependency checking to the compiler, use that
            for object, source in zip(objects, sources):
                depends = ext.depends + ext.includes[source]
                self.compiler.compile([source],
                                      output_dir=self.build_temp,
                                      macros=macros,
                                      include_dirs=ext.include_dirs,
                                      debug=self.debug,
                                      extra_postargs=extra_args,
                                      depends=depends)
        else:
            if not force:
                # Determine those sources that require rebuilding
                new_sources = []
                for object, source in zip(objects, sources):
                    depends = [source]
                    depends.extend(ext.includes[source])
                    if (newer_group(depends, object, 'newer')
                        or command_mtime > os.stat(object).st_mtime):
                        new_sources.append(source)
                sources = new_sources

            # Forcably build those sources listed in 'sources'
            self.compiler.force = True
            for source in sources:
                output_dir = os.path.join(self.build_temp,
                                          os.path.dirname(source))
                self.compiler.compile([source],
                                      output_dir=output_dir,
                                      macros=macros,
                                      include_dirs=ext.include_dirs,
                                      debug=self.debug,
                                      extra_postargs=extra_args)

        # Now link the object files together into a "shared object" --
        # of course, first we have to figure out all the other things
        # that go into the mix.
        if ext.extra_objects:
            objects.extend(ext.extra_objects)

        # Setup "symbol stripping"
        if self.symbol_stripping == STRIP_VERSIONING:
            # Strip symbols via a versioning script
            f, mapfile = self._mkstemp(ext, '.map')
            f.write('{ global: ')
            for sym in self.get_export_symbols(ext):
                f.write(sym + '; ')
            f.write('local: *; };')
            f.close()
            link_preargs = [self.strip_command % mapfile]

        elif self.symbol_stripping == STRIP_EXPORTS_FILE:
            # Strip symbols via an exports file
            f, expfile = self._mkstemp(ext, '.exp')
            for sym in self.get_export_symbols(ext):
                f.write(sym + '\n')
            f.close()
            link_preargs = [self.strip_command % expfile]

        elif self.symbol_stripping == STRIP_EXPORTS_ARGLIST:
            # Strip symbols via multiple arguments
            symbols = self.get_export_symbols(ext)
            link_preargs = [ self.strip_command % sym for sym in symbols ]

        else:
            # No linker support for limiting exported symbols
            link_preargs = []

        # Detect target language, if not provided
        kwords = {}
        if sys.version >= '2.3':
            lang = ext.language or self.compiler.detect_language(ext.sources)
            kwords['target_lang'] = lang

        self.compiler.link_shared_object(
            objects, ext_filename,
            libraries=self.get_libraries(ext),
            library_dirs=ext.library_dirs,
            runtime_library_dirs=ext.runtime_library_dirs,
            extra_preargs=link_preargs,
            extra_postargs=ext.extra_link_args,
            export_symbols=self.get_export_symbols(ext),
            debug=self.debug,
            build_temp=self.build_temp,
            **kwords)

        if self.symbol_stripping == STRIP_EXPORTS_POST_LINK:
            # Create the exports file
            f, expfile = self._mkstemp(ext, '.exp')
            for sym in self.get_export_symbols(ext):
                f.write(sym + '\n')
            f.close()

            subst = {'exports' : expfile, 'extension' : filename}
            self.spawn([ x % subst for x in self.strip_command.split(' ') ])

        # Reset the force flag on the compilier
        self.compiler.force = self.force
        return

    def prepare_sources(self, extension):
        """Walk the list of source files in 'sources', looking for SWIG
        interface (.i) files.  Run SWIG on all that are found, and
        return a modified 'sources' list with SWIG source files replaced
        by the generated C (or C++) files.
        """
        sources = []
        bgen_sources = []
        bgen_outputs = []
        for source in extension.sources:
            if source.endswith('.bgen'):
                name, includes = self._parse_bgen(source)
                if name is None:
                    name = extension.name.split('.')[-1][:-1]
                extension.includes[source] = includes
                # replace the BisonGen file with the generated C file
                bgen_output = os.path.dirname(source)
                bgen_output = os.path.join(bgen_output, name + '.c')
                # see if the C file needs to be regenerated
                if newer_group([source] + includes, bgen_output):
                    bgen_sources.append(source)
                bgen_outputs.append(bgen_output)
                sources.append(bgen_output)
            else:
                sources.append(source)
        if bgen_sources:
            try:
                from BisonGen import __version__,Processor,OptionParser
            except ImportError:
                # use the pre-generated sources
                for source in bgen_sources:
                    self.warn("not compiling %s (BisonGen not found)" % source)
            else:
                if StrictVersion(__version__) < BISONGEN_MINIMUM_VERSION:
                    raise DistutilsExecError("requires BisonGen %s, found %s"
                                             % (BISONGEN_MINIMUM_VERSION,
                                                __version__))
                # Convert verbosity to logging threshold
                threshold = 3 - self.verbose
                processor = Processor.Processor(threshold)
                options = OptionParser.Values()
                options.language = 'c'
                for source in bgen_sources:
                    options.outputDirectory = os.path.dirname(source)
                    processor.run(source, options)

        # Update the extension's include mapping for the generated file.
        for output in bgen_outputs:
            includes = extension.includes.get(output, [])
            includes = FindIncludes(output, extension.include_dirs, includes)
            extension.includes[output] = includes

        if sys.version < '2.4':
            return self.swig_sources(sources)
        return self.swig_sources(sources, extension)

    def _parse_bgen(self, filename):
        name = None
        includes = []
        basedir = os.path.dirname(filename)
        for event, node in Util.IterXml(filename):
            if name is None and event == 'START_ELEMENT':
                if node.tagName == 'options':
                    name = node.getAttribute('name')
            elif event == 'PROCESSING_INSTRUCTION':
                if node.target == 'include':
                    match = re.match(r'(["]?)(.+)(\1)', node.nodeValue)
                    if match:
                        include = util.convert_path(match.group(2))
                        include = os.path.join(basedir, include)
                        include = os.path.normpath(include)
                        includes.append(include)
                        includes.extend(self._parse_bgen(include)[1])
        return (name, includes)

    def _mkstemp(self, extension, suffix):
        path_parts = extension.name.split('.')
        basename = os.path.join(self.build_temp, *path_parts)
        # extensions in debug_mode are named 'module_d.pyd' under windows
        if os.name == 'nt' and self.debug:
            basename += '_d'
        filename = basename + suffix
        self.mkpath(os.path.dirname(filename))
        return (open(filename, 'w'), filename)

    def get_export_symbols(self, extension):
        symbols = build_ext.build_ext.get_export_symbols(self, extension)
        return [ self.export_symbol_format % symbol for symbol in symbols ]
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.