Home | History | Annotate | Download | only in command
      1 """distutils.command.build_ext
      2 
      3 Implements the Distutils 'build_ext' command, for building extension
      4 modules (currently limited to C extensions, should accommodate C++
      5 extensions ASAP)."""
      6 
      7 import contextlib
      8 import os
      9 import re
     10 import sys
     11 from distutils.core import Command
     12 from distutils.errors import *
     13 from distutils.sysconfig import customize_compiler, get_python_version
     14 from distutils.sysconfig import get_config_h_filename
     15 from distutils.dep_util import newer_group
     16 from distutils.extension import Extension
     17 from distutils.util import get_platform
     18 from distutils import log
     19 
     20 from site import USER_BASE
     21 
     22 # An extension name is just a dot-separated list of Python NAMEs (ie.
     23 # the same as a fully-qualified module name).
     24 extension_name_re = re.compile \
     25     (r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$')
     26 
     27 
     28 def show_compilers ():
     29     from distutils.ccompiler import show_compilers
     30     show_compilers()
     31 
     32 
     33 class build_ext(Command):
     34 
     35     description = "build C/C++ extensions (compile/link to build directory)"
     36 
     37     # XXX thoughts on how to deal with complex command-line options like
     38     # these, i.e. how to make it so fancy_getopt can suck them off the
     39     # command line and make it look like setup.py defined the appropriate
     40     # lists of tuples of what-have-you.
     41     #   - each command needs a callback to process its command-line options
     42     #   - Command.__init__() needs access to its share of the whole
     43     #     command line (must ultimately come from
     44     #     Distribution.parse_command_line())
     45     #   - it then calls the current command class' option-parsing
     46     #     callback to deal with weird options like -D, which have to
     47     #     parse the option text and churn out some custom data
     48     #     structure
     49     #   - that data structure (in this case, a list of 2-tuples)
     50     #     will then be present in the command object by the time
     51     #     we get to finalize_options() (i.e. the constructor
     52     #     takes care of both command-line and client options
     53     #     in between initialize_options() and finalize_options())
     54 
     55     sep_by = " (separated by '%s')" % os.pathsep
     56     user_options = [
     57         ('build-lib=', 'b',
     58          "directory for compiled extension modules"),
     59         ('build-temp=', 't',
     60          "directory for temporary files (build by-products)"),
     61         ('plat-name=', 'p',
     62          "platform name to cross-compile for, if supported "
     63          "(default: %s)" % get_platform()),
     64         ('inplace', 'i',
     65          "ignore build-lib and put compiled extensions into the source " +
     66          "directory alongside your pure Python modules"),
     67         ('include-dirs=', 'I',
     68          "list of directories to search for header files" + sep_by),
     69         ('define=', 'D',
     70          "C preprocessor macros to define"),
     71         ('undef=', 'U',
     72          "C preprocessor macros to undefine"),
     73         ('libraries=', 'l',
     74          "external C libraries to link with"),
     75         ('library-dirs=', 'L',
     76          "directories to search for external C libraries" + sep_by),
     77         ('rpath=', 'R',
     78          "directories to search for shared C libraries at runtime"),
     79         ('link-objects=', 'O',
     80          "extra explicit link objects to include in the link"),
     81         ('debug', 'g',
     82          "compile/link with debugging information"),
     83         ('force', 'f',
     84          "forcibly build everything (ignore file timestamps)"),
     85         ('compiler=', 'c',
     86          "specify the compiler type"),
     87         ('parallel=', 'j',
     88          "number of parallel build jobs"),
     89         ('swig-cpp', None,
     90          "make SWIG create C++ files (default is C)"),
     91         ('swig-opts=', None,
     92          "list of SWIG command line options"),
     93         ('swig=', None,
     94          "path to the SWIG executable"),
     95         ('user', None,
     96          "add user include, library and rpath")
     97         ]
     98 
     99     boolean_options = ['inplace', 'debug', 'force', 'swig-cpp', 'user']
    100 
    101     help_options = [
    102         ('help-compiler', None,
    103          "list available compilers", show_compilers),
    104         ]
    105 
    106     def initialize_options(self):
    107         self.extensions = None
    108         self.build_lib = None
    109         self.plat_name = None
    110         self.build_temp = None
    111         self.inplace = 0
    112         self.package = None
    113 
    114         self.include_dirs = None
    115         self.define = None
    116         self.undef = None
    117         self.libraries = None
    118         self.library_dirs = None
    119         self.rpath = None
    120         self.link_objects = None
    121         self.debug = None
    122         self.force = None
    123         self.compiler = None
    124         self.swig = None
    125         self.swig_cpp = None
    126         self.swig_opts = None
    127         self.user = None
    128         self.parallel = None
    129 
    130     def finalize_options(self):
    131         from distutils import sysconfig
    132 
    133         self.set_undefined_options('build',
    134                                    ('build_lib', 'build_lib'),
    135                                    ('build_temp', 'build_temp'),
    136                                    ('compiler', 'compiler'),
    137                                    ('debug', 'debug'),
    138                                    ('force', 'force'),
    139                                    ('parallel', 'parallel'),
    140                                    ('plat_name', 'plat_name'),
    141                                    )
    142 
    143         if self.package is None:
    144             self.package = self.distribution.ext_package
    145 
    146         self.extensions = self.distribution.ext_modules
    147 
    148         # Make sure Python's include directories (for Python.h, pyconfig.h,
    149         # etc.) are in the include search path.
    150         py_include = sysconfig.get_python_inc()
    151         plat_py_include = sysconfig.get_python_inc(plat_specific=1)
    152         if self.include_dirs is None:
    153             self.include_dirs = self.distribution.include_dirs or []
    154         if isinstance(self.include_dirs, str):
    155             self.include_dirs = self.include_dirs.split(os.pathsep)
    156 
    157         # If in a virtualenv, add its include directory
    158         # Issue 16116
    159         if sys.exec_prefix != sys.base_exec_prefix:
    160             self.include_dirs.append(os.path.join(sys.exec_prefix, 'include'))
    161 
    162         # Put the Python "system" include dir at the end, so that
    163         # any local include dirs take precedence.
    164         self.include_dirs.append(py_include)
    165         if plat_py_include != py_include:
    166             self.include_dirs.append(plat_py_include)
    167 
    168         self.ensure_string_list('libraries')
    169         self.ensure_string_list('link_objects')
    170 
    171         # Life is easier if we're not forever checking for None, so
    172         # simplify these options to empty lists if unset
    173         if self.libraries is None:
    174             self.libraries = []
    175         if self.library_dirs is None:
    176             self.library_dirs = []
    177         elif isinstance(self.library_dirs, str):
    178             self.library_dirs = self.library_dirs.split(os.pathsep)
    179 
    180         if self.rpath is None:
    181             self.rpath = []
    182         elif isinstance(self.rpath, str):
    183             self.rpath = self.rpath.split(os.pathsep)
    184 
    185         # for extensions under windows use different directories
    186         # for Release and Debug builds.
    187         # also Python's library directory must be appended to library_dirs
    188         if os.name == 'nt':
    189             # the 'libs' directory is for binary installs - we assume that
    190             # must be the *native* platform.  But we don't really support
    191             # cross-compiling via a binary install anyway, so we let it go.
    192             self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs'))
    193             if sys.base_exec_prefix != sys.prefix:  # Issue 16116
    194                 self.library_dirs.append(os.path.join(sys.base_exec_prefix, 'libs'))
    195             if self.debug:
    196                 self.build_temp = os.path.join(self.build_temp, "Debug")
    197             else:
    198                 self.build_temp = os.path.join(self.build_temp, "Release")
    199 
    200             # Append the source distribution include and library directories,
    201             # this allows distutils on windows to work in the source tree
    202             self.include_dirs.append(os.path.dirname(get_config_h_filename()))
    203             _sys_home = getattr(sys, '_home', None)
    204             if _sys_home:
    205                 self.library_dirs.append(_sys_home)
    206 
    207             # Use the .lib files for the correct architecture
    208             if self.plat_name == 'win32':
    209                 suffix = 'win32'
    210             else:
    211                 # win-amd64 or win-ia64
    212                 suffix = self.plat_name[4:]
    213             new_lib = os.path.join(sys.exec_prefix, 'PCbuild')
    214             if suffix:
    215                 new_lib = os.path.join(new_lib, suffix)
    216             self.library_dirs.append(new_lib)
    217 
    218         # for extensions under Cygwin and AtheOS Python's library directory must be
    219         # appended to library_dirs
    220         if sys.platform[:6] == 'cygwin' or sys.platform[:6] == 'atheos':
    221             if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")):
    222                 # building third party extensions
    223                 self.library_dirs.append(os.path.join(sys.prefix, "lib",
    224                                                       "python" + get_python_version(),
    225                                                       "config"))
    226             else:
    227                 # building python standard extensions
    228                 self.library_dirs.append('.')
    229 
    230         # For building extensions with a shared Python library,
    231         # Python's library directory must be appended to library_dirs
    232         # See Issues: #1600860, #4366
    233         if (sysconfig.get_config_var('Py_ENABLE_SHARED')):
    234             if not sysconfig.python_build:
    235                 # building third party extensions
    236                 self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
    237             else:
    238                 # building python standard extensions
    239                 self.library_dirs.append('.')
    240 
    241         # The argument parsing will result in self.define being a string, but
    242         # it has to be a list of 2-tuples.  All the preprocessor symbols
    243         # specified by the 'define' option will be set to '1'.  Multiple
    244         # symbols can be separated with commas.
    245 
    246         if self.define:
    247             defines = self.define.split(',')
    248             self.define = [(symbol, '1') for symbol in defines]
    249 
    250         # The option for macros to undefine is also a string from the
    251         # option parsing, but has to be a list.  Multiple symbols can also
    252         # be separated with commas here.
    253         if self.undef:
    254             self.undef = self.undef.split(',')
    255 
    256         if self.swig_opts is None:
    257             self.swig_opts = []
    258         else:
    259             self.swig_opts = self.swig_opts.split(' ')
    260 
    261         # Finally add the user include and library directories if requested
    262         if self.user:
    263             user_include = os.path.join(USER_BASE, "include")
    264             user_lib = os.path.join(USER_BASE, "lib")
    265             if os.path.isdir(user_include):
    266                 self.include_dirs.append(user_include)
    267             if os.path.isdir(user_lib):
    268                 self.library_dirs.append(user_lib)
    269                 self.rpath.append(user_lib)
    270 
    271         if isinstance(self.parallel, str):
    272             try:
    273                 self.parallel = int(self.parallel)
    274             except ValueError:
    275                 raise DistutilsOptionError("parallel should be an integer")
    276 
    277     def run(self):
    278         from distutils.ccompiler import new_compiler
    279 
    280         # 'self.extensions', as supplied by setup.py, is a list of
    281         # Extension instances.  See the documentation for Extension (in
    282         # distutils.extension) for details.
    283         #
    284         # For backwards compatibility with Distutils 0.8.2 and earlier, we
    285         # also allow the 'extensions' list to be a list of tuples:
    286         #    (ext_name, build_info)
    287         # where build_info is a dictionary containing everything that
    288         # Extension instances do except the name, with a few things being
    289         # differently named.  We convert these 2-tuples to Extension
    290         # instances as needed.
    291 
    292         if not self.extensions:
    293             return
    294 
    295         # If we were asked to build any C/C++ libraries, make sure that the
    296         # directory where we put them is in the library search path for
    297         # linking extensions.
    298         if self.distribution.has_c_libraries():
    299             build_clib = self.get_finalized_command('build_clib')
    300             self.libraries.extend(build_clib.get_library_names() or [])
    301             self.library_dirs.append(build_clib.build_clib)
    302 
    303         # Setup the CCompiler object that we'll use to do all the
    304         # compiling and linking
    305         self.compiler = new_compiler(compiler=self.compiler,
    306                                      verbose=self.verbose,
    307                                      dry_run=self.dry_run,
    308                                      force=self.force)
    309         customize_compiler(self.compiler)
    310         # If we are cross-compiling, init the compiler now (if we are not
    311         # cross-compiling, init would not hurt, but people may rely on
    312         # late initialization of compiler even if they shouldn't...)
    313         if os.name == 'nt' and self.plat_name != get_platform():
    314             self.compiler.initialize(self.plat_name)
    315 
    316         # And make sure that any compile/link-related options (which might
    317         # come from the command-line or from the setup script) are set in
    318         # that CCompiler object -- that way, they automatically apply to
    319         # all compiling and linking done here.
    320         if self.include_dirs is not None:
    321             self.compiler.set_include_dirs(self.include_dirs)
    322         if self.define is not None:
    323             # 'define' option is a list of (name,value) tuples
    324             for (name, value) in self.define:
    325                 self.compiler.define_macro(name, value)
    326         if self.undef is not None:
    327             for macro in self.undef:
    328                 self.compiler.undefine_macro(macro)
    329         if self.libraries is not None:
    330             self.compiler.set_libraries(self.libraries)
    331         if self.library_dirs is not None:
    332             self.compiler.set_library_dirs(self.library_dirs)
    333         if self.rpath is not None:
    334             self.compiler.set_runtime_library_dirs(self.rpath)
    335         if self.link_objects is not None:
    336             self.compiler.set_link_objects(self.link_objects)
    337 
    338         # Now actually compile and link everything.
    339         self.build_extensions()
    340 
    341     def check_extensions_list(self, extensions):
    342         """Ensure that the list of extensions (presumably provided as a
    343         command option 'extensions') is valid, i.e. it is a list of
    344         Extension objects.  We also support the old-style list of 2-tuples,
    345         where the tuples are (ext_name, build_info), which are converted to
    346         Extension instances here.
    347 
    348         Raise DistutilsSetupError if the structure is invalid anywhere;
    349         just returns otherwise.
    350         """
    351         if not isinstance(extensions, list):
    352             raise DistutilsSetupError(
    353                   "'ext_modules' option must be a list of Extension instances")
    354 
    355         for i, ext in enumerate(extensions):
    356             if isinstance(ext, Extension):
    357                 continue                # OK! (assume type-checking done
    358                                         # by Extension constructor)
    359 
    360             if not isinstance(ext, tuple) or len(ext) != 2:
    361                 raise DistutilsSetupError(
    362                        "each element of 'ext_modules' option must be an "
    363                        "Extension instance or 2-tuple")
    364 
    365             ext_name, build_info = ext
    366 
    367             log.warn("old-style (ext_name, build_info) tuple found in "
    368                      "ext_modules for extension '%s'"
    369                      "-- please convert to Extension instance", ext_name)
    370 
    371             if not (isinstance(ext_name, str) and
    372                     extension_name_re.match(ext_name)):
    373                 raise DistutilsSetupError(
    374                        "first element of each tuple in 'ext_modules' "
    375                        "must be the extension name (a string)")
    376 
    377             if not isinstance(build_info, dict):
    378                 raise DistutilsSetupError(
    379                        "second element of each tuple in 'ext_modules' "
    380                        "must be a dictionary (build info)")
    381 
    382             # OK, the (ext_name, build_info) dict is type-safe: convert it
    383             # to an Extension instance.
    384             ext = Extension(ext_name, build_info['sources'])
    385 
    386             # Easy stuff: one-to-one mapping from dict elements to
    387             # instance attributes.
    388             for key in ('include_dirs', 'library_dirs', 'libraries',
    389                         'extra_objects', 'extra_compile_args',
    390                         'extra_link_args'):
    391                 val = build_info.get(key)
    392                 if val is not None:
    393                     setattr(ext, key, val)
    394 
    395             # Medium-easy stuff: same syntax/semantics, different names.
    396             ext.runtime_library_dirs = build_info.get('rpath')
    397             if 'def_file' in build_info:
    398                 log.warn("'def_file' element of build info dict "
    399                          "no longer supported")
    400 
    401             # Non-trivial stuff: 'macros' split into 'define_macros'
    402             # and 'undef_macros'.
    403             macros = build_info.get('macros')
    404             if macros:
    405                 ext.define_macros = []
    406                 ext.undef_macros = []
    407                 for macro in macros:
    408                     if not (isinstance(macro, tuple) and len(macro) in (1, 2)):
    409                         raise DistutilsSetupError(
    410                               "'macros' element of build info dict "
    411                               "must be 1- or 2-tuple")
    412                     if len(macro) == 1:
    413                         ext.undef_macros.append(macro[0])
    414                     elif len(macro) == 2:
    415                         ext.define_macros.append(macro)
    416 
    417             extensions[i] = ext
    418 
    419     def get_source_files(self):
    420         self.check_extensions_list(self.extensions)
    421         filenames = []
    422 
    423         # Wouldn't it be neat if we knew the names of header files too...
    424         for ext in self.extensions:
    425             filenames.extend(ext.sources)
    426         return filenames
    427 
    428     def get_outputs(self):
    429         # Sanity check the 'extensions' list -- can't assume this is being
    430         # done in the same run as a 'build_extensions()' call (in fact, we
    431         # can probably assume that it *isn't*!).
    432         self.check_extensions_list(self.extensions)
    433 
    434         # And build the list of output (built) filenames.  Note that this
    435         # ignores the 'inplace' flag, and assumes everything goes in the
    436         # "build" tree.
    437         outputs = []
    438         for ext in self.extensions:
    439             outputs.append(self.get_ext_fullpath(ext.name))
    440         return outputs
    441 
    442     def build_extensions(self):
    443         # First, sanity-check the 'extensions' list
    444         self.check_extensions_list(self.extensions)
    445         if self.parallel:
    446             self._build_extensions_parallel()
    447         else:
    448             self._build_extensions_serial()
    449 
    450     def _build_extensions_parallel(self):
    451         workers = self.parallel
    452         if self.parallel is True:
    453             workers = os.cpu_count()  # may return None
    454         try:
    455             from concurrent.futures import ThreadPoolExecutor
    456         except ImportError:
    457             workers = None
    458 
    459         if workers is None:
    460             self._build_extensions_serial()
    461             return
    462 
    463         with ThreadPoolExecutor(max_workers=workers) as executor:
    464             futures = [executor.submit(self.build_extension, ext)
    465                        for ext in self.extensions]
    466             for ext, fut in zip(self.extensions, futures):
    467                 with self._filter_build_errors(ext):
    468                     fut.result()
    469 
    470     def _build_extensions_serial(self):
    471         for ext in self.extensions:
    472             with self._filter_build_errors(ext):
    473                 self.build_extension(ext)
    474 
    475     @contextlib.contextmanager
    476     def _filter_build_errors(self, ext):
    477         try:
    478             yield
    479         except (CCompilerError, DistutilsError, CompileError) as e:
    480             if not ext.optional:
    481                 raise
    482             self.warn('building extension "%s" failed: %s' %
    483                       (ext.name, e))
    484 
    485     def build_extension(self, ext):
    486         sources = ext.sources
    487         if sources is None or not isinstance(sources, (list, tuple)):
    488             raise DistutilsSetupError(
    489                   "in 'ext_modules' option (extension '%s'), "
    490                   "'sources' must be present and must be "
    491                   "a list of source filenames" % ext.name)
    492         sources = list(sources)
    493 
    494         ext_path = self.get_ext_fullpath(ext.name)
    495         depends = sources + ext.depends
    496         if not (self.force or newer_group(depends, ext_path, 'newer')):
    497             log.debug("skipping '%s' extension (up-to-date)", ext.name)
    498             return
    499         else:
    500             log.info("building '%s' extension", ext.name)
    501 
    502         # First, scan the sources for SWIG definition files (.i), run
    503         # SWIG on 'em to create .c files, and modify the sources list
    504         # accordingly.
    505         sources = self.swig_sources(sources, ext)
    506 
    507         # Next, compile the source code to object files.
    508 
    509         # XXX not honouring 'define_macros' or 'undef_macros' -- the
    510         # CCompiler API needs to change to accommodate this, and I
    511         # want to do one thing at a time!
    512 
    513         # Two possible sources for extra compiler arguments:
    514         #   - 'extra_compile_args' in Extension object
    515         #   - CFLAGS environment variable (not particularly
    516         #     elegant, but people seem to expect it and I
    517         #     guess it's useful)
    518         # The environment variable should take precedence, and
    519         # any sensible compiler will give precedence to later
    520         # command line args.  Hence we combine them in order:
    521         extra_args = ext.extra_compile_args or []
    522 
    523         macros = ext.define_macros[:]
    524         for undef in ext.undef_macros:
    525             macros.append((undef,))
    526 
    527         objects = self.compiler.compile(sources,
    528                                          output_dir=self.build_temp,
    529                                          macros=macros,
    530                                          include_dirs=ext.include_dirs,
    531                                          debug=self.debug,
    532                                          extra_postargs=extra_args,
    533                                          depends=ext.depends)
    534 
    535         # XXX outdated variable, kept here in case third-part code
    536         # needs it.
    537         self._built_objects = objects[:]
    538 
    539         # Now link the object files together into a "shared object" --
    540         # of course, first we have to figure out all the other things
    541         # that go into the mix.
    542         if ext.extra_objects:
    543             objects.extend(ext.extra_objects)
    544         extra_args = ext.extra_link_args or []
    545 
    546         # Detect target language, if not provided
    547         language = ext.language or self.compiler.detect_language(sources)
    548 
    549         self.compiler.link_shared_object(
    550             objects, ext_path,
    551             libraries=self.get_libraries(ext),
    552             library_dirs=ext.library_dirs,
    553             runtime_library_dirs=ext.runtime_library_dirs,
    554             extra_postargs=extra_args,
    555             export_symbols=self.get_export_symbols(ext),
    556             debug=self.debug,
    557             build_temp=self.build_temp,
    558             target_lang=language)
    559 
    560     def swig_sources(self, sources, extension):
    561         """Walk the list of source files in 'sources', looking for SWIG
    562         interface (.i) files.  Run SWIG on all that are found, and
    563         return a modified 'sources' list with SWIG source files replaced
    564         by the generated C (or C++) files.
    565         """
    566         new_sources = []
    567         swig_sources = []
    568         swig_targets = {}
    569 
    570         # XXX this drops generated C/C++ files into the source tree, which
    571         # is fine for developers who want to distribute the generated
    572         # source -- but there should be an option to put SWIG output in
    573         # the temp dir.
    574 
    575         if self.swig_cpp:
    576             log.warn("--swig-cpp is deprecated - use --swig-opts=-c++")
    577 
    578         if self.swig_cpp or ('-c++' in self.swig_opts) or \
    579            ('-c++' in extension.swig_opts):
    580             target_ext = '.cpp'
    581         else:
    582             target_ext = '.c'
    583 
    584         for source in sources:
    585             (base, ext) = os.path.splitext(source)
    586             if ext == ".i":             # SWIG interface file
    587                 new_sources.append(base + '_wrap' + target_ext)
    588                 swig_sources.append(source)
    589                 swig_targets[source] = new_sources[-1]
    590             else:
    591                 new_sources.append(source)
    592 
    593         if not swig_sources:
    594             return new_sources
    595 
    596         swig = self.swig or self.find_swig()
    597         swig_cmd = [swig, "-python"]
    598         swig_cmd.extend(self.swig_opts)
    599         if self.swig_cpp:
    600             swig_cmd.append("-c++")
    601 
    602         # Do not override commandline arguments
    603         if not self.swig_opts:
    604             for o in extension.swig_opts:
    605                 swig_cmd.append(o)
    606 
    607         for source in swig_sources:
    608             target = swig_targets[source]
    609             log.info("swigging %s to %s", source, target)
    610             self.spawn(swig_cmd + ["-o", target, source])
    611 
    612         return new_sources
    613 
    614     def find_swig(self):
    615         """Return the name of the SWIG executable.  On Unix, this is
    616         just "swig" -- it should be in the PATH.  Tries a bit harder on
    617         Windows.
    618         """
    619         if os.name == "posix":
    620             return "swig"
    621         elif os.name == "nt":
    622             # Look for SWIG in its standard installation directory on
    623             # Windows (or so I presume!).  If we find it there, great;
    624             # if not, act like Unix and assume it's in the PATH.
    625             for vers in ("1.3", "1.2", "1.1"):
    626                 fn = os.path.join("c:\\swig%s" % vers, "swig.exe")
    627                 if os.path.isfile(fn):
    628                     return fn
    629             else:
    630                 return "swig.exe"
    631         else:
    632             raise DistutilsPlatformError(
    633                   "I don't know how to find (much less run) SWIG "
    634                   "on platform '%s'" % os.name)
    635 
    636     # -- Name generators -----------------------------------------------
    637     # (extension names, filenames, whatever)
    638     def get_ext_fullpath(self, ext_name):
    639         """Returns the path of the filename for a given extension.
    640 
    641         The file is located in `build_lib` or directly in the package
    642         (inplace option).
    643         """
    644         fullname = self.get_ext_fullname(ext_name)
    645         modpath = fullname.split('.')
    646         filename = self.get_ext_filename(modpath[-1])
    647 
    648         if not self.inplace:
    649             # no further work needed
    650             # returning :
    651             #   build_dir/package/path/filename
    652             filename = os.path.join(*modpath[:-1]+[filename])
    653             return os.path.join(self.build_lib, filename)
    654 
    655         # the inplace option requires to find the package directory
    656         # using the build_py command for that
    657         package = '.'.join(modpath[0:-1])
    658         build_py = self.get_finalized_command('build_py')
    659         package_dir = os.path.abspath(build_py.get_package_dir(package))
    660 
    661         # returning
    662         #   package_dir/filename
    663         return os.path.join(package_dir, filename)
    664 
    665     def get_ext_fullname(self, ext_name):
    666         """Returns the fullname of a given extension name.
    667 
    668         Adds the `package.` prefix"""
    669         if self.package is None:
    670             return ext_name
    671         else:
    672             return self.package + '.' + ext_name
    673 
    674     def get_ext_filename(self, ext_name):
    675         r"""Convert the name of an extension (eg. "foo.bar") into the name
    676         of the file from which it will be loaded (eg. "foo/bar.so", or
    677         "foo\bar.pyd").
    678         """
    679         from distutils.sysconfig import get_config_var
    680         ext_path = ext_name.split('.')
    681         ext_suffix = get_config_var('EXT_SUFFIX')
    682         return os.path.join(*ext_path) + ext_suffix
    683 
    684     def get_export_symbols(self, ext):
    685         """Return the list of symbols that a shared extension has to
    686         export.  This either uses 'ext.export_symbols' or, if it's not
    687         provided, "PyInit_" + module_name.  Only relevant on Windows, where
    688         the .pyd file (DLL) must export the module "PyInit_" function.
    689         """
    690         initfunc_name = "PyInit_" + ext.name.split('.')[-1]
    691         if initfunc_name not in ext.export_symbols:
    692             ext.export_symbols.append(initfunc_name)
    693         return ext.export_symbols
    694 
    695     def get_libraries(self, ext):
    696         """Return the list of libraries to link against when building a
    697         shared extension.  On most platforms, this is just 'ext.libraries';
    698         on Windows, we add the Python library (eg. python20.dll).
    699         """
    700         # The python library is always needed on Windows.  For MSVC, this
    701         # is redundant, since the library is mentioned in a pragma in
    702         # pyconfig.h that MSVC groks.  The other Windows compilers all seem
    703         # to need it mentioned explicitly, though, so that's what we do.
    704         # Append '_d' to the python import library on debug builds.
    705         if sys.platform == "win32":
    706             from distutils._msvccompiler import MSVCCompiler
    707             if not isinstance(self.compiler, MSVCCompiler):
    708                 template = "python%d%d"
    709                 if self.debug:
    710                     template = template + '_d'
    711                 pythonlib = (template %
    712                        (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
    713                 # don't extend ext.libraries, it may be shared with other
    714                 # extensions, it is a reference to the original list
    715                 return ext.libraries + [pythonlib]
    716             else:
    717                 return ext.libraries
    718         elif sys.platform[:6] == "cygwin":
    719             template = "python%d.%d"
    720             pythonlib = (template %
    721                    (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
    722             # don't extend ext.libraries, it may be shared with other
    723             # extensions, it is a reference to the original list
    724             return ext.libraries + [pythonlib]
    725         elif sys.platform[:6] == "atheos":
    726             from distutils import sysconfig
    727 
    728             template = "python%d.%d"
    729             pythonlib = (template %
    730                    (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
    731             # Get SHLIBS from Makefile
    732             extra = []
    733             for lib in sysconfig.get_config_var('SHLIBS').split():
    734                 if lib.startswith('-l'):
    735                     extra.append(lib[2:])
    736                 else:
    737                     extra.append(lib)
    738             # don't extend ext.libraries, it may be shared with other
    739             # extensions, it is a reference to the original list
    740             return ext.libraries + [pythonlib, "m"] + extra
    741         elif sys.platform == 'darwin':
    742             # Don't use the default code below
    743             return ext.libraries
    744         elif sys.platform[:3] == 'aix':
    745             # Don't use the default code below
    746             return ext.libraries
    747         else:
    748             from distutils import sysconfig
    749             if sysconfig.get_config_var('Py_ENABLE_SHARED'):
    750                 pythonlib = 'python{}.{}{}'.format(
    751                     sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff,
    752                     sysconfig.get_config_var('ABIFLAGS'))
    753                 return ext.libraries + [pythonlib]
    754             else:
    755                 return ext.libraries
    756