NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

build_ext.py (18893B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\distutils\command\build_ext.py
      2 __revision__ = '$Id: build_ext.py 87602 2011-01-01 04:24:26Z richard.tew $'
      3 import sys, os, string, re
      4 from types import *
      5 from site import USER_BASE, USER_SITE
      6 from distutils.core import Command
      7 from distutils.errors import *
      8 from distutils.sysconfig import customize_compiler, get_python_version
      9 from distutils.dep_util import newer_group
     10 from distutils.extension import Extension
     11 from distutils.util import get_platform
     12 from distutils import log
     13 if os.name == 'nt':
     14     from distutils.msvccompiler import get_build_version
     15     MSVC_VERSION = int(get_build_version())
     16 extension_name_re = re.compile('^[a-zA-Z_][a-zA-Z_0-9]*(\\.[a-zA-Z_][a-zA-Z_0-9]*)*$')
     17 
     18 def show_compilers():
     19     from distutils.ccompiler import show_compilers
     20     show_compilers()
     21 
     22 
     23 class build_ext(Command):
     24     description = 'build C/C++ extensions (compile/link to build directory)'
     25     sep_by = " (separated by '%s')" % os.pathsep
     26     user_options = [('build-lib=', 'b', 'directory for compiled extension modules'),
     27      ('build-temp=', 't', 'directory for temporary files (build by-products)'),
     28      ('plat-name=', 'p', 'platform name to cross-compile for, if supported (default: %s)' % get_platform()),
     29      ('inplace', 'i', 'ignore build-lib and put compiled extensions into the source ' + 'directory alongside your pure Python modules'),
     30      ('include-dirs=', 'I', 'list of directories to search for header files' + sep_by),
     31      ('define=', 'D', 'C preprocessor macros to define'),
     32      ('undef=', 'U', 'C preprocessor macros to undefine'),
     33      ('libraries=', 'l', 'external C libraries to link with'),
     34      ('library-dirs=', 'L', 'directories to search for external C libraries' + sep_by),
     35      ('rpath=', 'R', 'directories to search for shared C libraries at runtime'),
     36      ('link-objects=', 'O', 'extra explicit link objects to include in the link'),
     37      ('debug', 'g', 'compile/link with debugging information'),
     38      ('force', 'f', 'forcibly build everything (ignore file timestamps)'),
     39      ('compiler=', 'c', 'specify the compiler type'),
     40      ('swig-cpp', None, 'make SWIG create C++ files (default is C)'),
     41      ('swig-opts=', None, 'list of SWIG command line options'),
     42      ('swig=', None, 'path to the SWIG executable'),
     43      ('user', None, 'add user include, library and rpath')]
     44     boolean_options = ['inplace',
     45      'debug',
     46      'force',
     47      'swig-cpp',
     48      'user']
     49     help_options = [('help-compiler',
     50       None,
     51       'list available compilers',
     52       show_compilers)]
     53 
     54     def initialize_options(self):
     55         self.extensions = None
     56         self.build_lib = None
     57         self.plat_name = None
     58         self.build_temp = None
     59         self.inplace = 0
     60         self.package = None
     61         self.include_dirs = None
     62         self.define = None
     63         self.undef = None
     64         self.libraries = None
     65         self.library_dirs = None
     66         self.rpath = None
     67         self.link_objects = None
     68         self.debug = None
     69         self.force = None
     70         self.compiler = None
     71         self.swig = None
     72         self.swig_cpp = None
     73         self.swig_opts = None
     74         self.user = None
     75 
     76     def finalize_options(self):
     77         from distutils import sysconfig
     78         self.set_undefined_options('build', ('build_lib', 'build_lib'), ('build_temp', 'build_temp'), ('compiler', 'compiler'), ('debug', 'debug'), ('force', 'force'), ('plat_name', 'plat_name'))
     79         if self.package is None:
     80             self.package = self.distribution.ext_package
     81         self.extensions = self.distribution.ext_modules
     82         py_include = sysconfig.get_python_inc()
     83         plat_py_include = sysconfig.get_python_inc(plat_specific=1)
     84         if self.include_dirs is None:
     85             self.include_dirs = self.distribution.include_dirs or []
     86         if isinstance(self.include_dirs, str):
     87             self.include_dirs = self.include_dirs.split(os.pathsep)
     88         self.include_dirs.append(py_include)
     89         if plat_py_include != py_include:
     90             self.include_dirs.append(plat_py_include)
     91         slpy_include = os.path.join(sysconfig.PREFIX, 'Stackless')
     92         if os.path.exists(slpy_include):
     93             self.include_dirs.append(slpy_include)
     94         else:
     95             slpy_include = os.path.join(py_include, 'Stackless')
     96             if os.path.exists(slpy_include):
     97                 self.include_dirs.append(slpy_include)
     98         if isinstance(self.libraries, str):
     99             self.libraries = [self.libraries]
    100         if self.libraries is None:
    101             self.libraries = []
    102         if self.library_dirs is None:
    103             self.library_dirs = []
    104         elif type(self.library_dirs) is StringType:
    105             self.library_dirs = string.split(self.library_dirs, os.pathsep)
    106         if self.rpath is None:
    107             self.rpath = []
    108         elif type(self.rpath) is StringType:
    109             self.rpath = string.split(self.rpath, os.pathsep)
    110         if os.name == 'nt':
    111             self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs'))
    112             if self.debug:
    113                 self.build_temp = os.path.join(self.build_temp, 'Debug')
    114             else:
    115                 self.build_temp = os.path.join(self.build_temp, 'Release')
    116             self.include_dirs.append(os.path.join(sys.exec_prefix, 'PC'))
    117             if MSVC_VERSION == 9:
    118                 if self.plat_name == 'win32':
    119                     suffix = ''
    120                 else:
    121                     suffix = self.plat_name[4:]
    122                 new_lib = os.path.join(sys.exec_prefix, 'PCbuild')
    123                 if suffix:
    124                     new_lib = os.path.join(new_lib, suffix)
    125                 self.library_dirs.append(new_lib)
    126             elif MSVC_VERSION == 8:
    127                 self.library_dirs.append(os.path.join(sys.exec_prefix, 'PC', 'VS8.0', 'win32release'))
    128             elif MSVC_VERSION == 7:
    129                 self.library_dirs.append(os.path.join(sys.exec_prefix, 'PC', 'VS7.1'))
    130             else:
    131                 self.library_dirs.append(os.path.join(sys.exec_prefix, 'PC', 'VC6'))
    132         if os.name == 'os2':
    133             self.library_dirs.append(os.path.join(sys.exec_prefix, 'Config'))
    134         if sys.platform[:6] == 'cygwin' or sys.platform[:6] == 'atheos':
    135             if sys.executable.startswith(os.path.join(sys.exec_prefix, 'bin')):
    136                 self.library_dirs.append(os.path.join(sys.prefix, 'lib', 'python' + get_python_version(), 'config'))
    137             else:
    138                 self.library_dirs.append('.')
    139         sysconfig.get_config_var('Py_ENABLE_SHARED')
    140         if (sys.platform.startswith('linux') or sys.platform.startswith('gnu') or sys.platform.startswith('sunos')) and sysconfig.get_config_var('Py_ENABLE_SHARED'):
    141             if sys.executable.startswith(os.path.join(sys.exec_prefix, 'bin')):
    142                 self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
    143             else:
    144                 self.library_dirs.append('.')
    145         if self.define:
    146             defines = self.define.split(',')
    147             self.define = map(lambda symbol: (symbol, '1'), defines)
    148         if self.undef:
    149             self.undef = self.undef.split(',')
    150         if self.swig_opts is None:
    151             self.swig_opts = []
    152         else:
    153             self.swig_opts = self.swig_opts.split(' ')
    154         if self.user:
    155             user_include = os.path.join(USER_BASE, 'include')
    156             user_lib = os.path.join(USER_BASE, 'lib')
    157             if os.path.isdir(user_include):
    158                 self.include_dirs.append(user_include)
    159             if os.path.isdir(user_lib):
    160                 self.library_dirs.append(user_lib)
    161                 self.rpath.append(user_lib)
    162 
    163     def run(self):
    164         from distutils.ccompiler import new_compiler
    165         if not self.extensions:
    166             return
    167         if self.distribution.has_c_libraries():
    168             build_clib = self.get_finalized_command('build_clib')
    169             self.libraries.extend(build_clib.get_library_names() or [])
    170             self.library_dirs.append(build_clib.build_clib)
    171         self.compiler = new_compiler(compiler=self.compiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force)
    172         customize_compiler(self.compiler)
    173         if os.name == 'nt' and self.plat_name != get_platform():
    174             self.compiler.initialize(self.plat_name)
    175         if self.include_dirs is not None:
    176             self.compiler.set_include_dirs(self.include_dirs)
    177         if self.define is not None:
    178             for name, value in self.define:
    179                 self.compiler.define_macro(name, value)
    180 
    181         if self.undef is not None:
    182             for macro in self.undef:
    183                 self.compiler.undefine_macro(macro)
    184 
    185         if self.libraries is not None:
    186             self.compiler.set_libraries(self.libraries)
    187         if self.library_dirs is not None:
    188             self.compiler.set_library_dirs(self.library_dirs)
    189         if self.rpath is not None:
    190             self.compiler.set_runtime_library_dirs(self.rpath)
    191         if self.link_objects is not None:
    192             self.compiler.set_link_objects(self.link_objects)
    193         self.build_extensions()
    194 
    195     def check_extensions_list(self, extensions):
    196         if not isinstance(extensions, list):
    197             raise DistutilsSetupError, "'ext_modules' option must be a list of Extension instances"
    198         for i, ext in enumerate(extensions):
    199             if isinstance(ext, Extension):
    200                 continue
    201             if not isinstance(ext, tuple) or len(ext) != 2:
    202                 raise DistutilsSetupError, "each element of 'ext_modules' option must be an Extension instance or 2-tuple"
    203             ext_name, build_info = ext
    204             log.warn("old-style (ext_name, build_info) tuple found in ext_modules for extension '%s'-- please convert to Extension instance" % ext_name)
    205             if not (isinstance(ext_name, str) and extension_name_re.match(ext_name)):
    206                 raise DistutilsSetupError, "first element of each tuple in 'ext_modules' must be the extension name (a string)"
    207             if not isinstance(build_info, dict):
    208                 raise DistutilsSetupError, "second element of each tuple in 'ext_modules' must be a dictionary (build info)"
    209             ext = Extension(ext_name, build_info['sources'])
    210             for key in ('include_dirs', 'library_dirs', 'libraries', 'extra_objects', 'extra_compile_args', 'extra_link_args'):
    211                 val = build_info.get(key)
    212                 if val is not None:
    213                     setattr(ext, key, val)
    214 
    215             ext.runtime_library_dirs = build_info.get('rpath')
    216             if 'def_file' in build_info:
    217                 log.warn("'def_file' element of build info dict no longer supported")
    218             macros = build_info.get('macros')
    219             if macros:
    220                 ext.define_macros = []
    221                 ext.undef_macros = []
    222                 for macro in macros:
    223                     if not (isinstance(macro, tuple) and len(macro) in (1, 2)):
    224                         raise DistutilsSetupError, "'macros' element of build info dict must be 1- or 2-tuple"
    225                     if len(macro) == 1:
    226                         ext.undef_macros.append(macro[0])
    227                     elif len(macro) == 2:
    228                         ext.define_macros.append(macro)
    229 
    230             extensions[i] = ext
    231 
    232     def get_source_files(self):
    233         self.check_extensions_list(self.extensions)
    234         filenames = []
    235         for ext in self.extensions:
    236             filenames.extend(ext.sources)
    237 
    238         return filenames
    239 
    240     def get_outputs(self):
    241         self.check_extensions_list(self.extensions)
    242         outputs = []
    243         for ext in self.extensions:
    244             outputs.append(self.get_ext_fullpath(ext.name))
    245 
    246         return outputs
    247 
    248     def build_extensions(self):
    249         self.check_extensions_list(self.extensions)
    250         for ext in self.extensions:
    251             self.build_extension(ext)
    252 
    253     def build_extension(self, ext):
    254         sources = ext.sources
    255         if sources is None or type(sources) not in (ListType, TupleType):
    256             raise DistutilsSetupError, ("in 'ext_modules' option (extension '%s'), " + "'sources' must be present and must be " + 'a list of source filenames') % ext.name
    257         sources = list(sources)
    258         ext_path = self.get_ext_fullpath(ext.name)
    259         depends = sources + ext.depends
    260         if not (self.force or newer_group(depends, ext_path, 'newer')):
    261             log.debug("skipping '%s' extension (up-to-date)", ext.name)
    262             return
    263         log.info("building '%s' extension", ext.name)
    264         sources = self.swig_sources(sources, ext)
    265         extra_args = ext.extra_compile_args or []
    266         macros = ext.define_macros[:]
    267         for undef in ext.undef_macros:
    268             macros.append((undef,))
    269 
    270         objects = self.compiler.compile(sources, output_dir=self.build_temp, macros=macros, include_dirs=ext.include_dirs, debug=self.debug, extra_postargs=extra_args, depends=ext.depends)
    271         self._built_objects = objects[:]
    272         if ext.extra_objects:
    273             objects.extend(ext.extra_objects)
    274         extra_args = ext.extra_link_args or []
    275         language = ext.language or self.compiler.detect_language(sources)
    276         self.compiler.link_shared_object(objects, ext_path, libraries=self.get_libraries(ext), library_dirs=ext.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, target_lang=language)
    277 
    278     def swig_sources(self, sources, extension):
    279         new_sources = []
    280         swig_sources = []
    281         swig_targets = {}
    282         if self.swig_cpp:
    283             log.warn('--swig-cpp is deprecated - use --swig-opts=-c++')
    284         if self.swig_cpp or '-c++' in self.swig_opts or '-c++' in extension.swig_opts:
    285             target_ext = '.cpp'
    286         else:
    287             target_ext = '.c'
    288         for source in sources:
    289             base, ext = os.path.splitext(source)
    290             if ext == '.i':
    291                 new_sources.append(base + '_wrap' + target_ext)
    292                 swig_sources.append(source)
    293                 swig_targets[source] = new_sources[-1]
    294             else:
    295                 new_sources.append(source)
    296 
    297         if not swig_sources:
    298             return new_sources
    299         swig = self.swig or self.find_swig()
    300         swig_cmd = [swig, '-python']
    301         swig_cmd.extend(self.swig_opts)
    302         if self.swig_cpp:
    303             swig_cmd.append('-c++')
    304         if not self.swig_opts:
    305             for o in extension.swig_opts:
    306                 swig_cmd.append(o)
    307 
    308         for source in swig_sources:
    309             target = swig_targets[source]
    310             log.info('swigging %s to %s', source, target)
    311             self.spawn(swig_cmd + ['-o', target, source])
    312 
    313         return new_sources
    314 
    315     def find_swig(self):
    316         if os.name == 'posix':
    317             return 'swig'
    318         if os.name == 'nt':
    319             for vers in ('1.3', '1.2', '1.1'):
    320                 fn = os.path.join('c:\\swig%s' % vers, 'swig.exe')
    321                 if os.path.isfile(fn):
    322                     return fn
    323             else:
    324                 return 'swig.exe'
    325 
    326         else:
    327             if os.name == 'os2':
    328                 return 'swig.exe'
    329             raise DistutilsPlatformError, "I don't know how to find (much less run) SWIG on platform '%s'" % os.name
    330 
    331     def get_ext_fullpath(self, ext_name):
    332         all_dots = string.maketrans('/' + os.sep, '..')
    333         ext_name = ext_name.translate(all_dots)
    334         fullname = self.get_ext_fullname(ext_name)
    335         modpath = fullname.split('.')
    336         filename = self.get_ext_filename(ext_name)
    337         filename = os.path.split(filename)[-1]
    338         if not self.inplace:
    339             filename = os.path.join(*(modpath[:-1] + [filename]))
    340             return os.path.join(self.build_lib, filename)
    341         package = '.'.join(modpath[0:-1])
    342         build_py = self.get_finalized_command('build_py')
    343         package_dir = os.path.abspath(build_py.get_package_dir(package))
    344         return os.path.join(package_dir, filename)
    345 
    346     def get_ext_fullname(self, ext_name):
    347         if self.package is None:
    348             return ext_name
    349         else:
    350             return self.package + '.' + ext_name
    351 
    352     def get_ext_filename(self, ext_name):
    353         from distutils.sysconfig import get_config_var
    354         ext_path = string.split(ext_name, '.')
    355         if os.name == 'os2':
    356             ext_path[len(ext_path) - 1] = ext_path[len(ext_path) - 1][:8]
    357         so_ext = get_config_var('SO')
    358         if os.name == 'nt' and self.debug:
    359             return os.path.join(*ext_path) + '_d' + so_ext
    360         return os.path.join(*ext_path) + so_ext
    361 
    362     def get_export_symbols(self, ext):
    363         initfunc_name = 'init' + ext.name.split('.')[-1]
    364         if initfunc_name not in ext.export_symbols:
    365             ext.export_symbols.append(initfunc_name)
    366         return ext.export_symbols
    367 
    368     def get_libraries(self, ext):
    369         if sys.platform == 'win32':
    370             from distutils.msvccompiler import MSVCCompiler
    371             if not isinstance(self.compiler, MSVCCompiler):
    372                 template = 'python%d%d'
    373                 if self.debug:
    374                     template = template + '_d'
    375                 pythonlib = template % (sys.hexversion >> 24, sys.hexversion >> 16 & 255)
    376                 return ext.libraries + [pythonlib]
    377             else:
    378                 return ext.libraries
    379         else:
    380             if sys.platform == 'os2emx':
    381                 template = 'python%d%d'
    382                 pythonlib = template % (sys.hexversion >> 24, sys.hexversion >> 16 & 255)
    383                 return ext.libraries + [pythonlib]
    384             if sys.platform[:6] == 'cygwin':
    385                 template = 'python%d.%d'
    386                 pythonlib = template % (sys.hexversion >> 24, sys.hexversion >> 16 & 255)
    387                 return ext.libraries + [pythonlib]
    388             if sys.platform[:6] == 'atheos':
    389                 from distutils import sysconfig
    390                 template = 'python%d.%d'
    391                 pythonlib = template % (sys.hexversion >> 24, sys.hexversion >> 16 & 255)
    392                 extra = []
    393                 for lib in sysconfig.get_config_var('SHLIBS').split():
    394                     if lib.startswith('-l'):
    395                         extra.append(lib[2:])
    396                     else:
    397                         extra.append(lib)
    398 
    399                 return ext.libraries + [pythonlib, 'm'] + extra
    400             if sys.platform == 'darwin':
    401                 return ext.libraries
    402             if sys.platform[:3] == 'aix':
    403                 return ext.libraries
    404             from distutils import sysconfig
    405             if sysconfig.get_config_var('Py_ENABLE_SHARED'):
    406                 template = 'python%d.%d'
    407                 pythonlib = template % (sys.hexversion >> 24, sys.hexversion >> 16 & 255)
    408                 return ext.libraries + [pythonlib]
    409             return ext.libraries