Path: blob/main/test/lib/python3.9/site-packages/setuptools/_distutils/sysconfig.py
4799 views
"""Provide access to Python's configuration information. The specific1configuration variables available depend heavily on the platform and2configuration. The values may be retrieved using3get_config_var(name), and the list of variables is available via4get_config_vars().keys(). Additional convenience functions are also5available.67Written by: Fred L. Drake, Jr.8Email: <[email protected]>9"""1011import os12import re13import sys14import sysconfig1516from .errors import DistutilsPlatformError17from . import py39compat18from ._functools import pass_none1920IS_PYPY = '__pypy__' in sys.builtin_module_names2122# These are needed in a couple of spots, so just compute them once.23PREFIX = os.path.normpath(sys.prefix)24EXEC_PREFIX = os.path.normpath(sys.exec_prefix)25BASE_PREFIX = os.path.normpath(sys.base_prefix)26BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)2728# Path to the base directory of the project. On Windows the binary may29# live in project/PCbuild/win32 or project/PCbuild/amd64.30# set for cross builds31if "_PYTHON_PROJECT_BASE" in os.environ:32project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"])33else:34if sys.executable:35project_base = os.path.dirname(os.path.abspath(sys.executable))36else:37# sys.executable can be empty if argv[0] has been changed and Python is38# unable to retrieve the real program name39project_base = os.getcwd()404142# python_build: (Boolean) if true, we're either building Python or43# building an extension with an un-installed Python, so we use44# different (hard-wired) directories.45def _is_python_source_dir(d):46for fn in ("Setup", "Setup.local"):47if os.path.isfile(os.path.join(d, "Modules", fn)):48return True49return False505152_sys_home = getattr(sys, '_home', None)535455def _is_parent(dir_a, dir_b):56"""57Return True if a is a parent of b.58"""59return os.path.normcase(dir_a).startswith(os.path.normcase(dir_b))606162if os.name == 'nt':63@pass_none64def _fix_pcbuild(d):65# In a venv, sys._home will be inside BASE_PREFIX rather than PREFIX.66prefixes = PREFIX, BASE_PREFIX67matched = (68prefix69for prefix in prefixes70if _is_parent(d, os.path.join(prefix, "PCbuild"))71)72return next(matched, d)73project_base = _fix_pcbuild(project_base)74_sys_home = _fix_pcbuild(_sys_home)757677def _python_build():78if _sys_home:79return _is_python_source_dir(_sys_home)80return _is_python_source_dir(project_base)818283python_build = _python_build()848586# Calculate the build qualifier flags if they are defined. Adding the flags87# to the include and lib directories only makes sense for an installation, not88# an in-source build.89build_flags = ''90try:91if not python_build:92build_flags = sys.abiflags93except AttributeError:94# It's not a configure-based build, so the sys module doesn't have95# this attribute, which is fine.96pass979899def get_python_version():100"""Return a string containing the major and minor Python version,101leaving off the patchlevel. Sample return values could be '1.5'102or '2.2'.103"""104return '%d.%d' % sys.version_info[:2]105106107def get_python_inc(plat_specific=0, prefix=None):108"""Return the directory containing installed Python header files.109110If 'plat_specific' is false (the default), this is the path to the111non-platform-specific header files, i.e. Python.h and so on;112otherwise, this is the path to platform-specific header files113(namely pyconfig.h).114115If 'prefix' is supplied, use it instead of sys.base_prefix or116sys.base_exec_prefix -- i.e., ignore 'plat_specific'.117"""118if prefix is None:119prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX120if os.name == "posix":121if IS_PYPY and sys.version_info < (3, 8):122return os.path.join(prefix, 'include')123if python_build:124# Assume the executable is in the build directory. The125# pyconfig.h file should be in the same directory. Since126# the build directory may not be the source directory, we127# must use "srcdir" from the makefile to find the "Include"128# directory.129if plat_specific:130return _sys_home or project_base131else:132incdir = os.path.join(get_config_var('srcdir'), 'Include')133return os.path.normpath(incdir)134implementation = 'pypy' if IS_PYPY else 'python'135python_dir = implementation + get_python_version() + build_flags136return os.path.join(prefix, "include", python_dir)137elif os.name == "nt":138if python_build:139# Include both the include and PC dir to ensure we can find140# pyconfig.h141return (os.path.join(prefix, "include") + os.path.pathsep +142os.path.join(prefix, "PC"))143return os.path.join(prefix, "include")144else:145raise DistutilsPlatformError(146"I don't know where Python installs its C header files "147"on platform '%s'" % os.name)148149150# allow this behavior to be monkey-patched. Ref pypa/distutils#2.151def _posix_lib(standard_lib, libpython, early_prefix, prefix):152if standard_lib:153return libpython154else:155return os.path.join(libpython, "site-packages")156157158def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):159"""Return the directory containing the Python library (standard or160site additions).161162If 'plat_specific' is true, return the directory containing163platform-specific modules, i.e. any module from a non-pure-Python164module distribution; otherwise, return the platform-shared library165directory. If 'standard_lib' is true, return the directory166containing standard Python library modules; otherwise, return the167directory for site-specific modules.168169If 'prefix' is supplied, use it instead of sys.base_prefix or170sys.base_exec_prefix -- i.e., ignore 'plat_specific'.171"""172173if IS_PYPY and sys.version_info < (3, 8):174# PyPy-specific schema175if prefix is None:176prefix = PREFIX177if standard_lib:178return os.path.join(prefix, "lib-python", sys.version[0])179return os.path.join(prefix, 'site-packages')180181early_prefix = prefix182183if prefix is None:184if standard_lib:185prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX186else:187prefix = plat_specific and EXEC_PREFIX or PREFIX188189if os.name == "posix":190if plat_specific or standard_lib:191# Platform-specific modules (any module from a non-pure-Python192# module distribution) or standard Python library modules.193libdir = getattr(sys, "platlibdir", "lib")194else:195# Pure Python196libdir = "lib"197implementation = 'pypy' if IS_PYPY else 'python'198libpython = os.path.join(prefix, libdir,199implementation + get_python_version())200return _posix_lib(standard_lib, libpython, early_prefix, prefix)201elif os.name == "nt":202if standard_lib:203return os.path.join(prefix, "Lib")204else:205return os.path.join(prefix, "Lib", "site-packages")206else:207raise DistutilsPlatformError(208"I don't know where Python installs its library "209"on platform '%s'" % os.name)210211212def customize_compiler(compiler):213"""Do any platform-specific customization of a CCompiler instance.214215Mainly needed on Unix, so we can plug in the information that216varies across Unices and is stored in Python's Makefile.217"""218if compiler.compiler_type == "unix":219if sys.platform == "darwin":220# Perform first-time customization of compiler-related221# config vars on OS X now that we know we need a compiler.222# This is primarily to support Pythons from binary223# installers. The kind and paths to build tools on224# the user system may vary significantly from the system225# that Python itself was built on. Also the user OS226# version and build tools may not support the same set227# of CPU architectures for universal builds.228global _config_vars229# Use get_config_var() to ensure _config_vars is initialized.230if not get_config_var('CUSTOMIZED_OSX_COMPILER'):231import _osx_support232_osx_support.customize_compiler(_config_vars)233_config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'234235(cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \236get_config_vars(237'CC', 'CXX', 'CFLAGS',238'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')239240if 'CC' in os.environ:241newcc = os.environ['CC']242if('LDSHARED' not in os.environ243and ldshared.startswith(cc)):244# If CC is overridden, use that as the default245# command for LDSHARED as well246ldshared = newcc + ldshared[len(cc):]247cc = newcc248if 'CXX' in os.environ:249cxx = os.environ['CXX']250if 'LDSHARED' in os.environ:251ldshared = os.environ['LDSHARED']252if 'CPP' in os.environ:253cpp = os.environ['CPP']254else:255cpp = cc + " -E" # not always256if 'LDFLAGS' in os.environ:257ldshared = ldshared + ' ' + os.environ['LDFLAGS']258if 'CFLAGS' in os.environ:259cflags = cflags + ' ' + os.environ['CFLAGS']260ldshared = ldshared + ' ' + os.environ['CFLAGS']261if 'CPPFLAGS' in os.environ:262cpp = cpp + ' ' + os.environ['CPPFLAGS']263cflags = cflags + ' ' + os.environ['CPPFLAGS']264ldshared = ldshared + ' ' + os.environ['CPPFLAGS']265if 'AR' in os.environ:266ar = os.environ['AR']267if 'ARFLAGS' in os.environ:268archiver = ar + ' ' + os.environ['ARFLAGS']269else:270archiver = ar + ' ' + ar_flags271272cc_cmd = cc + ' ' + cflags273compiler.set_executables(274preprocessor=cpp,275compiler=cc_cmd,276compiler_so=cc_cmd + ' ' + ccshared,277compiler_cxx=cxx,278linker_so=ldshared,279linker_exe=cc,280archiver=archiver)281282if 'RANLIB' in os.environ and compiler.executables.get('ranlib', None):283compiler.set_executables(ranlib=os.environ['RANLIB'])284285compiler.shared_lib_extension = shlib_suffix286287288def get_config_h_filename():289"""Return full pathname of installed pyconfig.h file."""290if python_build:291if os.name == "nt":292inc_dir = os.path.join(_sys_home or project_base, "PC")293else:294inc_dir = _sys_home or project_base295return os.path.join(inc_dir, 'pyconfig.h')296else:297return sysconfig.get_config_h_filename()298299300def get_makefile_filename():301"""Return full pathname of installed Makefile from the Python build."""302return sysconfig.get_makefile_filename()303304305def parse_config_h(fp, g=None):306"""Parse a config.h-style file.307308A dictionary containing name/value pairs is returned. If an309optional dictionary is passed in as the second argument, it is310used instead of a new dictionary.311"""312return sysconfig.parse_config_h(fp, vars=g)313314315# Regexes needed for parsing Makefile (and similar syntaxes,316# like old-style Setup files).317_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")318_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")319_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")320321322def parse_makefile(fn, g=None):323"""Parse a Makefile-style file.324325A dictionary containing name/value pairs is returned. If an326optional dictionary is passed in as the second argument, it is327used instead of a new dictionary.328"""329from distutils.text_file import TextFile330fp = TextFile(331fn, strip_comments=1, skip_blanks=1, join_lines=1,332errors="surrogateescape")333334if g is None:335g = {}336done = {}337notdone = {}338339while True:340line = fp.readline()341if line is None: # eof342break343m = _variable_rx.match(line)344if m:345n, v = m.group(1, 2)346v = v.strip()347# `$$' is a literal `$' in make348tmpv = v.replace('$$', '')349350if "$" in tmpv:351notdone[n] = v352else:353try:354v = int(v)355except ValueError:356# insert literal `$'357done[n] = v.replace('$$', '$')358else:359done[n] = v360361# Variables with a 'PY_' prefix in the makefile. These need to362# be made available without that prefix through sysconfig.363# Special care is needed to ensure that variable expansion works, even364# if the expansion uses the name without a prefix.365renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')366367# do variable interpolation here368while notdone:369for name in list(notdone):370value = notdone[name]371m = _findvar1_rx.search(value) or _findvar2_rx.search(value)372if m:373n = m.group(1)374found = True375if n in done:376item = str(done[n])377elif n in notdone:378# get it on a subsequent round379found = False380elif n in os.environ:381# do it like make: fall back to environment382item = os.environ[n]383384elif n in renamed_variables:385if name.startswith('PY_') and \386name[3:] in renamed_variables:387item = ""388389elif 'PY_' + n in notdone:390found = False391392else:393item = str(done['PY_' + n])394else:395done[n] = item = ""396if found:397after = value[m.end():]398value = value[:m.start()] + item + after399if "$" in after:400notdone[name] = value401else:402try:403value = int(value)404except ValueError:405done[name] = value.strip()406else:407done[name] = value408del notdone[name]409410if name.startswith('PY_') \411and name[3:] in renamed_variables:412413name = name[3:]414if name not in done:415done[name] = value416else:417# bogus variable reference; just drop it since we can't deal418del notdone[name]419420fp.close()421422# strip spurious spaces423for k, v in done.items():424if isinstance(v, str):425done[k] = v.strip()426427# save the results in the global dictionary428g.update(done)429return g430431432def expand_makefile_vars(s, vars):433"""Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in434'string' according to 'vars' (a dictionary mapping variable names to435values). Variables not present in 'vars' are silently expanded to the436empty string. The variable values in 'vars' should not contain further437variable expansions; if 'vars' is the output of 'parse_makefile()',438you're fine. Returns a variable-expanded version of 's'.439"""440441# This algorithm does multiple expansion, so if vars['foo'] contains442# "${bar}", it will expand ${foo} to ${bar}, and then expand443# ${bar}... and so forth. This is fine as long as 'vars' comes from444# 'parse_makefile()', which takes care of such expansions eagerly,445# according to make's variable expansion semantics.446447while True:448m = _findvar1_rx.search(s) or _findvar2_rx.search(s)449if m:450(beg, end) = m.span()451s = s[0:beg] + vars.get(m.group(1)) + s[end:]452else:453break454return s455456457_config_vars = None458459460def get_config_vars(*args):461"""With no arguments, return a dictionary of all configuration462variables relevant for the current platform. Generally this includes463everything needed to build extensions and install both pure modules and464extensions. On Unix, this means every variable defined in Python's465installed Makefile; on Windows it's a much smaller set.466467With arguments, return a list of values that result from looking up468each argument in the configuration variable dictionary.469"""470global _config_vars471if _config_vars is None:472_config_vars = sysconfig.get_config_vars().copy()473py39compat.add_ext_suffix(_config_vars)474475if args:476vals = []477for name in args:478vals.append(_config_vars.get(name))479return vals480else:481return _config_vars482483484def get_config_var(name):485"""Return the value of a single variable using the dictionary486returned by 'get_config_vars()'. Equivalent to487get_config_vars().get(name)488"""489if name == 'SO':490import warnings491warnings.warn(492'SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)493return get_config_vars().get(name)494495496