Path: blob/main/test/lib/python3.9/site-packages/setuptools/command/build_ext.py
4799 views
import os1import sys2import itertools3from importlib.machinery import EXTENSION_SUFFIXES4from distutils.command.build_ext import build_ext as _du_build_ext5from distutils.file_util import copy_file6from distutils.ccompiler import new_compiler7from distutils.sysconfig import customize_compiler, get_config_var8from distutils.errors import DistutilsError9from distutils import log1011from setuptools.extension import Library1213try:14# Attempt to use Cython for building extensions, if available15from Cython.Distutils.build_ext import build_ext as _build_ext16# Additionally, assert that the compiler module will load17# also. Ref #1229.18__import__('Cython.Compiler.Main')19except ImportError:20_build_ext = _du_build_ext2122# make sure _config_vars is initialized23get_config_var("LDSHARED")24from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa252627def _customize_compiler_for_shlib(compiler):28if sys.platform == "darwin":29# building .dylib requires additional compiler flags on OSX; here we30# temporarily substitute the pyconfig.h variables so that distutils'31# 'customize_compiler' uses them before we build the shared libraries.32tmp = _CONFIG_VARS.copy()33try:34# XXX Help! I don't have any idea whether these are right...35_CONFIG_VARS['LDSHARED'] = (36"gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")37_CONFIG_VARS['CCSHARED'] = " -dynamiclib"38_CONFIG_VARS['SO'] = ".dylib"39customize_compiler(compiler)40finally:41_CONFIG_VARS.clear()42_CONFIG_VARS.update(tmp)43else:44customize_compiler(compiler)454647have_rtld = False48use_stubs = False49libtype = 'shared'5051if sys.platform == "darwin":52use_stubs = True53elif os.name != 'nt':54try:55import dl56use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW')57except ImportError:58pass596061def if_dl(s):62return s if have_rtld else ''636465def get_abi3_suffix():66"""Return the file extension for an abi3-compliant Extension()"""67for suffix in EXTENSION_SUFFIXES:68if '.abi3' in suffix: # Unix69return suffix70elif suffix == '.pyd': # Windows71return suffix727374class build_ext(_build_ext):75def run(self):76"""Build extensions in build directory, then copy if --inplace"""77old_inplace, self.inplace = self.inplace, 078_build_ext.run(self)79self.inplace = old_inplace80if old_inplace:81self.copy_extensions_to_source()8283def copy_extensions_to_source(self):84build_py = self.get_finalized_command('build_py')85for ext in self.extensions:86fullname = self.get_ext_fullname(ext.name)87filename = self.get_ext_filename(fullname)88modpath = fullname.split('.')89package = '.'.join(modpath[:-1])90package_dir = build_py.get_package_dir(package)91dest_filename = os.path.join(package_dir,92os.path.basename(filename))93src_filename = os.path.join(self.build_lib, filename)9495# Always copy, even if source is older than destination, to ensure96# that the right extensions for the current Python/platform are97# used.98copy_file(99src_filename, dest_filename, verbose=self.verbose,100dry_run=self.dry_run101)102if ext._needs_stub:103self.write_stub(package_dir or os.curdir, ext, True)104105def get_ext_filename(self, fullname):106so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX')107if so_ext:108filename = os.path.join(*fullname.split('.')) + so_ext109else:110filename = _build_ext.get_ext_filename(self, fullname)111so_ext = get_config_var('EXT_SUFFIX')112113if fullname in self.ext_map:114ext = self.ext_map[fullname]115use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix()116if use_abi3:117filename = filename[:-len(so_ext)]118so_ext = get_abi3_suffix()119filename = filename + so_ext120if isinstance(ext, Library):121fn, ext = os.path.splitext(filename)122return self.shlib_compiler.library_filename(fn, libtype)123elif use_stubs and ext._links_to_dynamic:124d, fn = os.path.split(filename)125return os.path.join(d, 'dl-' + fn)126return filename127128def initialize_options(self):129_build_ext.initialize_options(self)130self.shlib_compiler = None131self.shlibs = []132self.ext_map = {}133134def finalize_options(self):135_build_ext.finalize_options(self)136self.extensions = self.extensions or []137self.check_extensions_list(self.extensions)138self.shlibs = [ext for ext in self.extensions139if isinstance(ext, Library)]140if self.shlibs:141self.setup_shlib_compiler()142for ext in self.extensions:143ext._full_name = self.get_ext_fullname(ext.name)144for ext in self.extensions:145fullname = ext._full_name146self.ext_map[fullname] = ext147148# distutils 3.1 will also ask for module names149# XXX what to do with conflicts?150self.ext_map[fullname.split('.')[-1]] = ext151152ltd = self.shlibs and self.links_to_dynamic(ext) or False153ns = ltd and use_stubs and not isinstance(ext, Library)154ext._links_to_dynamic = ltd155ext._needs_stub = ns156filename = ext._file_name = self.get_ext_filename(fullname)157libdir = os.path.dirname(os.path.join(self.build_lib, filename))158if ltd and libdir not in ext.library_dirs:159ext.library_dirs.append(libdir)160if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:161ext.runtime_library_dirs.append(os.curdir)162163def setup_shlib_compiler(self):164compiler = self.shlib_compiler = new_compiler(165compiler=self.compiler, dry_run=self.dry_run, force=self.force166)167_customize_compiler_for_shlib(compiler)168169if self.include_dirs is not None:170compiler.set_include_dirs(self.include_dirs)171if self.define is not None:172# 'define' option is a list of (name,value) tuples173for (name, value) in self.define:174compiler.define_macro(name, value)175if self.undef is not None:176for macro in self.undef:177compiler.undefine_macro(macro)178if self.libraries is not None:179compiler.set_libraries(self.libraries)180if self.library_dirs is not None:181compiler.set_library_dirs(self.library_dirs)182if self.rpath is not None:183compiler.set_runtime_library_dirs(self.rpath)184if self.link_objects is not None:185compiler.set_link_objects(self.link_objects)186187# hack so distutils' build_extension() builds a library instead188compiler.link_shared_object = link_shared_object.__get__(compiler)189190def get_export_symbols(self, ext):191if isinstance(ext, Library):192return ext.export_symbols193return _build_ext.get_export_symbols(self, ext)194195def build_extension(self, ext):196ext._convert_pyx_sources_to_lang()197_compiler = self.compiler198try:199if isinstance(ext, Library):200self.compiler = self.shlib_compiler201_build_ext.build_extension(self, ext)202if ext._needs_stub:203cmd = self.get_finalized_command('build_py').build_lib204self.write_stub(cmd, ext)205finally:206self.compiler = _compiler207208def links_to_dynamic(self, ext):209"""Return true if 'ext' links to a dynamic lib in the same package"""210# XXX this should check to ensure the lib is actually being built211# XXX as dynamic, and not just using a locally-found version or a212# XXX static-compiled version213libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])214pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])215return any(pkg + libname in libnames for libname in ext.libraries)216217def get_outputs(self):218return _build_ext.get_outputs(self) + self.__get_stubs_outputs()219220def __get_stubs_outputs(self):221# assemble the base name for each extension that needs a stub222ns_ext_bases = (223os.path.join(self.build_lib, *ext._full_name.split('.'))224for ext in self.extensions225if ext._needs_stub226)227# pair each base with the extension228pairs = itertools.product(ns_ext_bases, self.__get_output_extensions())229return list(base + fnext for base, fnext in pairs)230231def __get_output_extensions(self):232yield '.py'233yield '.pyc'234if self.get_finalized_command('build_py').optimize:235yield '.pyo'236237def write_stub(self, output_dir, ext, compile=False):238log.info("writing stub loader for %s to %s", ext._full_name,239output_dir)240stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) +241'.py')242if compile and os.path.exists(stub_file):243raise DistutilsError(stub_file + " already exists! Please delete.")244if not self.dry_run:245f = open(stub_file, 'w')246f.write(247'\n'.join([248"def __bootstrap__():",249" global __bootstrap__, __file__, __loader__",250" import sys, os, pkg_resources, importlib.util" +251if_dl(", dl"),252" __file__ = pkg_resources.resource_filename"253"(__name__,%r)"254% os.path.basename(ext._file_name),255" del __bootstrap__",256" if '__loader__' in globals():",257" del __loader__",258if_dl(" old_flags = sys.getdlopenflags()"),259" old_dir = os.getcwd()",260" try:",261" os.chdir(os.path.dirname(__file__))",262if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),263" spec = importlib.util.spec_from_file_location(",264" __name__, __file__)",265" mod = importlib.util.module_from_spec(spec)",266" spec.loader.exec_module(mod)",267" finally:",268if_dl(" sys.setdlopenflags(old_flags)"),269" os.chdir(old_dir)",270"__bootstrap__()",271"" # terminal \n272])273)274f.close()275if compile:276from distutils.util import byte_compile277278byte_compile([stub_file], optimize=0,279force=True, dry_run=self.dry_run)280optimize = self.get_finalized_command('install_lib').optimize281if optimize > 0:282byte_compile([stub_file], optimize=optimize,283force=True, dry_run=self.dry_run)284if os.path.exists(stub_file) and not self.dry_run:285os.unlink(stub_file)286287288if use_stubs or os.name == 'nt':289# Build shared libraries290#291def link_shared_object(292self, objects, output_libname, output_dir=None, libraries=None,293library_dirs=None, runtime_library_dirs=None, export_symbols=None,294debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,295target_lang=None):296self.link(297self.SHARED_LIBRARY, objects, output_libname,298output_dir, libraries, library_dirs, runtime_library_dirs,299export_symbols, debug, extra_preargs, extra_postargs,300build_temp, target_lang301)302else:303# Build static libraries everywhere else304libtype = 'static'305306def link_shared_object(307self, objects, output_libname, output_dir=None, libraries=None,308library_dirs=None, runtime_library_dirs=None, export_symbols=None,309debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,310target_lang=None):311# XXX we need to either disallow these attrs on Library instances,312# or warn/abort here if set, or something...313# libraries=None, library_dirs=None, runtime_library_dirs=None,314# export_symbols=None, extra_preargs=None, extra_postargs=None,315# build_temp=None316317assert output_dir is None # distutils build_ext doesn't pass this318output_dir, filename = os.path.split(output_libname)319basename, ext = os.path.splitext(filename)320if self.library_filename("x").startswith('lib'):321# strip 'lib' prefix; this is kludgy if some platform uses322# a different prefix323basename = basename[3:]324325self.create_static_lib(326objects, basename, output_dir, debug, target_lang327)328329330