Path: blob/main/test/lib/python3.9/site-packages/setuptools/_distutils/unixccompiler.py
4799 views
"""distutils.unixccompiler12Contains the UnixCCompiler class, a subclass of CCompiler that handles3the "typical" Unix-style command-line C compiler:4* macros defined with -Dname[=value]5* macros undefined with -Uname6* include search directories specified with -Idir7* libraries specified with -lllib8* library search directories specified with -Ldir9* compile handled by 'cc' (or similar) executable with -c option:10compiles .c to .o11* link static library handled by 'ar' command (possibly with 'ranlib')12* link shared library handled by 'cc -shared'13"""1415import os, sys, re, shlex1617from distutils import sysconfig18from distutils.dep_util import newer19from distutils.ccompiler import \20CCompiler, gen_preprocess_options, gen_lib_options21from distutils.errors import \22DistutilsExecError, CompileError, LibError, LinkError23from distutils import log24from ._macos_compat import compiler_fixup2526# XXX Things not currently handled:27# * optimization/debug/warning flags; we just use whatever's in Python's28# Makefile and live with it. Is this adequate? If not, we might29# have to have a bunch of subclasses GNUCCompiler, SGICCompiler,30# SunCCompiler, and I suspect down that road lies madness.31# * even if we don't know a warning flag from an optimization flag,32# we need some way for outsiders to feed preprocessor/compiler/linker33# flags in to us -- eg. a sysadmin might want to mandate certain flags34# via a site config file, or a user might want to set something for35# compiling this module distribution only via the setup.py command36# line, whatever. As long as these options come from something on the37# current system, they can be as system-dependent as they like, and we38# should just happily stuff them into the preprocessor/compiler/linker39# options and carry on.404142def _split_env(cmd):43"""44For macOS, split command into 'env' portion (if any)45and the rest of the linker command.4647>>> _split_env(['a', 'b', 'c'])48([], ['a', 'b', 'c'])49>>> _split_env(['/usr/bin/env', 'A=3', 'gcc'])50(['/usr/bin/env', 'A=3'], ['gcc'])51"""52pivot = 053if os.path.basename(cmd[0]) == "env":54pivot = 155while '=' in cmd[pivot]:56pivot += 157return cmd[:pivot], cmd[pivot:]585960def _split_aix(cmd):61"""62AIX platforms prefix the compiler with the ld_so_aix63script, so split that from the linker command.6465>>> _split_aix(['a', 'b', 'c'])66([], ['a', 'b', 'c'])67>>> _split_aix(['/bin/foo/ld_so_aix', 'gcc'])68(['/bin/foo/ld_so_aix'], ['gcc'])69"""70pivot = os.path.basename(cmd[0]) == 'ld_so_aix'71return cmd[:pivot], cmd[pivot:]727374def _linker_params(linker_cmd, compiler_cmd):75"""76The linker command usually begins with the compiler77command (possibly multiple elements), followed by zero or more78params for shared library building.7980If the LDSHARED env variable overrides the linker command,81however, the commands may not match.8283Return the best guess of the linker parameters by stripping84the linker command. If the compiler command does not85match the linker command, assume the linker command is86just the first element.8788>>> _linker_params('gcc foo bar'.split(), ['gcc'])89['foo', 'bar']90>>> _linker_params('gcc foo bar'.split(), ['other'])91['foo', 'bar']92>>> _linker_params('ccache gcc foo bar'.split(), 'ccache gcc'.split())93['foo', 'bar']94>>> _linker_params(['gcc'], ['gcc'])95[]96"""97c_len = len(compiler_cmd)98pivot = c_len if linker_cmd[:c_len] == compiler_cmd else 199return linker_cmd[pivot:]100101102class UnixCCompiler(CCompiler):103104compiler_type = 'unix'105106# These are used by CCompiler in two places: the constructor sets107# instance attributes 'preprocessor', 'compiler', etc. from them, and108# 'set_executable()' allows any of these to be set. The defaults here109# are pretty generic; they will probably have to be set by an outsider110# (eg. using information discovered by the sysconfig about building111# Python extensions).112executables = {'preprocessor' : None,113'compiler' : ["cc"],114'compiler_so' : ["cc"],115'compiler_cxx' : ["cc"],116'linker_so' : ["cc", "-shared"],117'linker_exe' : ["cc"],118'archiver' : ["ar", "-cr"],119'ranlib' : None,120}121122if sys.platform[:6] == "darwin":123executables['ranlib'] = ["ranlib"]124125# Needed for the filename generation methods provided by the base126# class, CCompiler. NB. whoever instantiates/uses a particular127# UnixCCompiler instance should set 'shared_lib_ext' -- we set a128# reasonable common default here, but it's not necessarily used on all129# Unices!130131src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"]132obj_extension = ".o"133static_lib_extension = ".a"134shared_lib_extension = ".so"135dylib_lib_extension = ".dylib"136xcode_stub_lib_extension = ".tbd"137static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s"138xcode_stub_lib_format = dylib_lib_format139if sys.platform == "cygwin":140exe_extension = ".exe"141142def preprocess(self, source, output_file=None, macros=None,143include_dirs=None, extra_preargs=None, extra_postargs=None):144fixed_args = self._fix_compile_args(None, macros, include_dirs)145ignore, macros, include_dirs = fixed_args146pp_opts = gen_preprocess_options(macros, include_dirs)147pp_args = self.preprocessor + pp_opts148if output_file:149pp_args.extend(['-o', output_file])150if extra_preargs:151pp_args[:0] = extra_preargs152if extra_postargs:153pp_args.extend(extra_postargs)154pp_args.append(source)155156# We need to preprocess: either we're being forced to, or we're157# generating output to stdout, or there's a target output file and158# the source file is newer than the target (or the target doesn't159# exist).160if self.force or output_file is None or newer(source, output_file):161if output_file:162self.mkpath(os.path.dirname(output_file))163try:164self.spawn(pp_args)165except DistutilsExecError as msg:166raise CompileError(msg)167168def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):169compiler_so = compiler_fixup(170self.compiler_so, cc_args + extra_postargs)171try:172self.spawn(compiler_so + cc_args + [src, '-o', obj] +173extra_postargs)174except DistutilsExecError as msg:175raise CompileError(msg)176177def create_static_lib(self, objects, output_libname,178output_dir=None, debug=0, target_lang=None):179objects, output_dir = self._fix_object_args(objects, output_dir)180181output_filename = \182self.library_filename(output_libname, output_dir=output_dir)183184if self._need_link(objects, output_filename):185self.mkpath(os.path.dirname(output_filename))186self.spawn(self.archiver +187[output_filename] +188objects + self.objects)189190# Not many Unices required ranlib anymore -- SunOS 4.x is, I191# think the only major Unix that does. Maybe we need some192# platform intelligence here to skip ranlib if it's not193# needed -- or maybe Python's configure script took care of194# it for us, hence the check for leading colon.195if self.ranlib:196try:197self.spawn(self.ranlib + [output_filename])198except DistutilsExecError as msg:199raise LibError(msg)200else:201log.debug("skipping %s (up-to-date)", output_filename)202203def link(self, target_desc, objects,204output_filename, output_dir=None, libraries=None,205library_dirs=None, runtime_library_dirs=None,206export_symbols=None, debug=0, extra_preargs=None,207extra_postargs=None, build_temp=None, target_lang=None):208objects, output_dir = self._fix_object_args(objects, output_dir)209fixed_args = self._fix_lib_args(libraries, library_dirs,210runtime_library_dirs)211libraries, library_dirs, runtime_library_dirs = fixed_args212213lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs,214libraries)215if not isinstance(output_dir, (str, type(None))):216raise TypeError("'output_dir' must be a string or None")217if output_dir is not None:218output_filename = os.path.join(output_dir, output_filename)219220if self._need_link(objects, output_filename):221ld_args = (objects + self.objects +222lib_opts + ['-o', output_filename])223if debug:224ld_args[:0] = ['-g']225if extra_preargs:226ld_args[:0] = extra_preargs227if extra_postargs:228ld_args.extend(extra_postargs)229self.mkpath(os.path.dirname(output_filename))230try:231# Select a linker based on context: linker_exe when232# building an executable or linker_so (with shared options)233# when building a shared library.234building_exe = target_desc == CCompiler.EXECUTABLE235linker = (self.linker_exe if building_exe else self.linker_so)[:]236237if target_lang == "c++" and self.compiler_cxx:238env, linker_ne = _split_env(linker)239aix, linker_na = _split_aix(linker_ne)240_, compiler_cxx_ne = _split_env(self.compiler_cxx)241_, linker_exe_ne = _split_env(self.linker_exe)242243params = _linker_params(linker_na, linker_exe_ne)244linker = env + aix + compiler_cxx_ne + params245246linker = compiler_fixup(linker, ld_args)247248self.spawn(linker + ld_args)249except DistutilsExecError as msg:250raise LinkError(msg)251else:252log.debug("skipping %s (up-to-date)", output_filename)253254# -- Miscellaneous methods -----------------------------------------255# These are all used by the 'gen_lib_options() function, in256# ccompiler.py.257258def library_dir_option(self, dir):259return "-L" + dir260261def _is_gcc(self, compiler_name):262return "gcc" in compiler_name or "g++" in compiler_name263264def runtime_library_dir_option(self, dir):265# XXX Hackish, at the very least. See Python bug #445902:266# http://sourceforge.net/tracker/index.php267# ?func=detail&aid=445902&group_id=5470&atid=105470268# Linkers on different platforms need different options to269# specify that directories need to be added to the list of270# directories searched for dependencies when a dynamic library271# is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to272# be told to pass the -R option through to the linker, whereas273# other compilers and gcc on other systems just know this.274# Other compilers may need something slightly different. At275# this time, there's no way to determine this information from276# the configuration data stored in the Python installation, so277# we use this hack.278compiler = os.path.basename(shlex.split(sysconfig.get_config_var("CC"))[0])279if sys.platform[:6] == "darwin":280from distutils.util import get_macosx_target_ver, split_version281macosx_target_ver = get_macosx_target_ver()282if macosx_target_ver and split_version(macosx_target_ver) >= [10, 5]:283return "-Wl,-rpath," + dir284else: # no support for -rpath on earlier macOS versions285return "-L" + dir286elif sys.platform[:7] == "freebsd":287return "-Wl,-rpath=" + dir288elif sys.platform[:5] == "hp-ux":289if self._is_gcc(compiler):290return ["-Wl,+s", "-L" + dir]291return ["+s", "-L" + dir]292293# For all compilers, `-Wl` is the presumed way to294# pass a compiler option to the linker and `-R` is295# the way to pass an RPATH.296if sysconfig.get_config_var("GNULD") == "yes":297# GNU ld needs an extra option to get a RUNPATH298# instead of just an RPATH.299return "-Wl,--enable-new-dtags,-R" + dir300else:301return "-Wl,-R" + dir302303def library_option(self, lib):304return "-l" + lib305306def find_library_file(self, dirs, lib, debug=0):307shared_f = self.library_filename(lib, lib_type='shared')308dylib_f = self.library_filename(lib, lib_type='dylib')309xcode_stub_f = self.library_filename(lib, lib_type='xcode_stub')310static_f = self.library_filename(lib, lib_type='static')311312if sys.platform == 'darwin':313# On OSX users can specify an alternate SDK using314# '-isysroot', calculate the SDK root if it is specified315# (and use it further on)316#317# Note that, as of Xcode 7, Apple SDKs may contain textual stub318# libraries with .tbd extensions rather than the normal .dylib319# shared libraries installed in /. The Apple compiler tool320# chain handles this transparently but it can cause problems321# for programs that are being built with an SDK and searching322# for specific libraries. Callers of find_library_file need to323# keep in mind that the base filename of the returned SDK library324# file might have a different extension from that of the library325# file installed on the running system, for example:326# /Applications/Xcode.app/Contents/Developer/Platforms/327# MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/328# usr/lib/libedit.tbd329# vs330# /usr/lib/libedit.dylib331cflags = sysconfig.get_config_var('CFLAGS')332m = re.search(r'-isysroot\s*(\S+)', cflags)333if m is None:334sysroot = '/'335else:336sysroot = m.group(1)337338339340for dir in dirs:341shared = os.path.join(dir, shared_f)342dylib = os.path.join(dir, dylib_f)343static = os.path.join(dir, static_f)344xcode_stub = os.path.join(dir, xcode_stub_f)345346if sys.platform == 'darwin' and (347dir.startswith('/System/') or (348dir.startswith('/usr/') and not dir.startswith('/usr/local/'))):349350shared = os.path.join(sysroot, dir[1:], shared_f)351dylib = os.path.join(sysroot, dir[1:], dylib_f)352static = os.path.join(sysroot, dir[1:], static_f)353xcode_stub = os.path.join(sysroot, dir[1:], xcode_stub_f)354355# We're second-guessing the linker here, with not much hard356# data to go on: GCC seems to prefer the shared library, so I'm357# assuming that *all* Unix C compilers do. And of course I'm358# ignoring even GCC's "-static" option. So sue me.359if os.path.exists(dylib):360return dylib361elif os.path.exists(xcode_stub):362return xcode_stub363elif os.path.exists(shared):364return shared365elif os.path.exists(static):366return static367368# Oops, didn't find it in *any* of 'dirs'369return None370371372