Path: blob/master/venv/Lib/site-packages/setuptools/_distutils/sysconfig.py
811 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 _imp12import os13import re14import sys1516from .errors import DistutilsPlatformError1718IS_PYPY = '__pypy__' in sys.builtin_module_names1920# These are needed in a couple of spots, so just compute them once.21PREFIX = os.path.normpath(sys.prefix)22EXEC_PREFIX = os.path.normpath(sys.exec_prefix)23BASE_PREFIX = os.path.normpath(sys.base_prefix)24BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)2526# Path to the base directory of the project. On Windows the binary may27# live in project/PCbuild/win32 or project/PCbuild/amd64.28# set for cross builds29if "_PYTHON_PROJECT_BASE" in os.environ:30project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"])31else:32if sys.executable:33project_base = os.path.dirname(os.path.abspath(sys.executable))34else:35# sys.executable can be empty if argv[0] has been changed and Python is36# unable to retrieve the real program name37project_base = os.getcwd()383940# python_build: (Boolean) if true, we're either building Python or41# building an extension with an un-installed Python, so we use42# different (hard-wired) directories.43def _is_python_source_dir(d):44for fn in ("Setup", "Setup.local"):45if os.path.isfile(os.path.join(d, "Modules", fn)):46return True47return False4849_sys_home = getattr(sys, '_home', None)5051if os.name == 'nt':52def _fix_pcbuild(d):53if d and os.path.normcase(d).startswith(54os.path.normcase(os.path.join(PREFIX, "PCbuild"))):55return PREFIX56return d57project_base = _fix_pcbuild(project_base)58_sys_home = _fix_pcbuild(_sys_home)5960def _python_build():61if _sys_home:62return _is_python_source_dir(_sys_home)63return _is_python_source_dir(project_base)6465python_build = _python_build()666768# Calculate the build qualifier flags if they are defined. Adding the flags69# to the include and lib directories only makes sense for an installation, not70# an in-source build.71build_flags = ''72try:73if not python_build:74build_flags = sys.abiflags75except AttributeError:76# It's not a configure-based build, so the sys module doesn't have77# this attribute, which is fine.78pass7980def get_python_version():81"""Return a string containing the major and minor Python version,82leaving off the patchlevel. Sample return values could be '1.5'83or '2.2'.84"""85return '%d.%d' % sys.version_info[:2]868788def get_python_inc(plat_specific=0, prefix=None):89"""Return the directory containing installed Python header files.9091If 'plat_specific' is false (the default), this is the path to the92non-platform-specific header files, i.e. Python.h and so on;93otherwise, this is the path to platform-specific header files94(namely pyconfig.h).9596If 'prefix' is supplied, use it instead of sys.base_prefix or97sys.base_exec_prefix -- i.e., ignore 'plat_specific'.98"""99if prefix is None:100prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX101if IS_PYPY:102return os.path.join(prefix, 'include')103elif os.name == "posix":104if python_build:105# Assume the executable is in the build directory. The106# pyconfig.h file should be in the same directory. Since107# the build directory may not be the source directory, we108# must use "srcdir" from the makefile to find the "Include"109# directory.110if plat_specific:111return _sys_home or project_base112else:113incdir = os.path.join(get_config_var('srcdir'), 'Include')114return os.path.normpath(incdir)115python_dir = 'python' + get_python_version() + build_flags116return os.path.join(prefix, "include", python_dir)117elif os.name == "nt":118if python_build:119# Include both the include and PC dir to ensure we can find120# pyconfig.h121return (os.path.join(prefix, "include") + os.path.pathsep +122os.path.join(prefix, "PC"))123return os.path.join(prefix, "include")124else:125raise DistutilsPlatformError(126"I don't know where Python installs its C header files "127"on platform '%s'" % os.name)128129130def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):131"""Return the directory containing the Python library (standard or132site additions).133134If 'plat_specific' is true, return the directory containing135platform-specific modules, i.e. any module from a non-pure-Python136module distribution; otherwise, return the platform-shared library137directory. If 'standard_lib' is true, return the directory138containing standard Python library modules; otherwise, return the139directory for site-specific modules.140141If 'prefix' is supplied, use it instead of sys.base_prefix or142sys.base_exec_prefix -- i.e., ignore 'plat_specific'.143"""144if IS_PYPY:145# PyPy-specific schema146if prefix is None:147prefix = PREFIX148if standard_lib:149return os.path.join(prefix, "lib-python", sys.version[0])150return os.path.join(prefix, 'site-packages')151152if prefix is None:153if standard_lib:154prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX155else:156prefix = plat_specific and EXEC_PREFIX or PREFIX157158if os.name == "posix":159if plat_specific or standard_lib:160# Platform-specific modules (any module from a non-pure-Python161# module distribution) or standard Python library modules.162libdir = getattr(sys, "platlibdir", "lib")163else:164# Pure Python165libdir = "lib"166libpython = os.path.join(prefix, libdir,167"python" + get_python_version())168if standard_lib:169return libpython170else:171return os.path.join(libpython, "site-packages")172elif os.name == "nt":173if standard_lib:174return os.path.join(prefix, "Lib")175else:176return os.path.join(prefix, "Lib", "site-packages")177else:178raise DistutilsPlatformError(179"I don't know where Python installs its library "180"on platform '%s'" % os.name)181182183184def customize_compiler(compiler):185"""Do any platform-specific customization of a CCompiler instance.186187Mainly needed on Unix, so we can plug in the information that188varies across Unices and is stored in Python's Makefile.189"""190if compiler.compiler_type == "unix":191if sys.platform == "darwin":192# Perform first-time customization of compiler-related193# config vars on OS X now that we know we need a compiler.194# This is primarily to support Pythons from binary195# installers. The kind and paths to build tools on196# the user system may vary significantly from the system197# that Python itself was built on. Also the user OS198# version and build tools may not support the same set199# of CPU architectures for universal builds.200global _config_vars201# Use get_config_var() to ensure _config_vars is initialized.202if not get_config_var('CUSTOMIZED_OSX_COMPILER'):203import _osx_support204_osx_support.customize_compiler(_config_vars)205_config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'206207(cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \208get_config_vars('CC', 'CXX', 'CFLAGS',209'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')210211if 'CC' in os.environ:212newcc = os.environ['CC']213if (sys.platform == 'darwin'214and 'LDSHARED' not in os.environ215and ldshared.startswith(cc)):216# On OS X, if CC is overridden, use that as the default217# command for LDSHARED as well218ldshared = newcc + ldshared[len(cc):]219cc = newcc220if 'CXX' in os.environ:221cxx = os.environ['CXX']222if 'LDSHARED' in os.environ:223ldshared = os.environ['LDSHARED']224if 'CPP' in os.environ:225cpp = os.environ['CPP']226else:227cpp = cc + " -E" # not always228if 'LDFLAGS' in os.environ:229ldshared = ldshared + ' ' + os.environ['LDFLAGS']230if 'CFLAGS' in os.environ:231cflags = cflags + ' ' + os.environ['CFLAGS']232ldshared = ldshared + ' ' + os.environ['CFLAGS']233if 'CPPFLAGS' in os.environ:234cpp = cpp + ' ' + os.environ['CPPFLAGS']235cflags = cflags + ' ' + os.environ['CPPFLAGS']236ldshared = ldshared + ' ' + os.environ['CPPFLAGS']237if 'AR' in os.environ:238ar = os.environ['AR']239if 'ARFLAGS' in os.environ:240archiver = ar + ' ' + os.environ['ARFLAGS']241else:242archiver = ar + ' ' + ar_flags243244cc_cmd = cc + ' ' + cflags245compiler.set_executables(246preprocessor=cpp,247compiler=cc_cmd,248compiler_so=cc_cmd + ' ' + ccshared,249compiler_cxx=cxx,250linker_so=ldshared,251linker_exe=cc,252archiver=archiver)253254compiler.shared_lib_extension = shlib_suffix255256257def get_config_h_filename():258"""Return full pathname of installed pyconfig.h file."""259if python_build:260if os.name == "nt":261inc_dir = os.path.join(_sys_home or project_base, "PC")262else:263inc_dir = _sys_home or project_base264else:265inc_dir = get_python_inc(plat_specific=1)266267return os.path.join(inc_dir, 'pyconfig.h')268269270def get_makefile_filename():271"""Return full pathname of installed Makefile from the Python build."""272if python_build:273return os.path.join(_sys_home or project_base, "Makefile")274lib_dir = get_python_lib(plat_specific=0, standard_lib=1)275config_file = 'config-{}{}'.format(get_python_version(), build_flags)276if hasattr(sys.implementation, '_multiarch'):277config_file += '-%s' % sys.implementation._multiarch278return os.path.join(lib_dir, config_file, 'Makefile')279280281def parse_config_h(fp, g=None):282"""Parse a config.h-style file.283284A dictionary containing name/value pairs is returned. If an285optional dictionary is passed in as the second argument, it is286used instead of a new dictionary.287"""288if g is None:289g = {}290define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")291undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")292#293while True:294line = fp.readline()295if not line:296break297m = define_rx.match(line)298if m:299n, v = m.group(1, 2)300try: v = int(v)301except ValueError: pass302g[n] = v303else:304m = undef_rx.match(line)305if m:306g[m.group(1)] = 0307return g308309310# Regexes needed for parsing Makefile (and similar syntaxes,311# like old-style Setup files).312_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")313_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")314_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")315316def parse_makefile(fn, g=None):317"""Parse a Makefile-style file.318319A dictionary containing name/value pairs is returned. If an320optional dictionary is passed in as the second argument, it is321used instead of a new dictionary.322"""323from distutils.text_file import TextFile324fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape")325326if g is None:327g = {}328done = {}329notdone = {}330331while True:332line = fp.readline()333if line is None: # eof334break335m = _variable_rx.match(line)336if m:337n, v = m.group(1, 2)338v = v.strip()339# `$$' is a literal `$' in make340tmpv = v.replace('$$', '')341342if "$" in tmpv:343notdone[n] = v344else:345try:346v = int(v)347except ValueError:348# insert literal `$'349done[n] = v.replace('$$', '$')350else:351done[n] = v352353# Variables with a 'PY_' prefix in the makefile. These need to354# be made available without that prefix through sysconfig.355# Special care is needed to ensure that variable expansion works, even356# if the expansion uses the name without a prefix.357renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')358359# do variable interpolation here360while notdone:361for name in list(notdone):362value = notdone[name]363m = _findvar1_rx.search(value) or _findvar2_rx.search(value)364if m:365n = m.group(1)366found = True367if n in done:368item = str(done[n])369elif n in notdone:370# get it on a subsequent round371found = False372elif n in os.environ:373# do it like make: fall back to environment374item = os.environ[n]375376elif n in renamed_variables:377if name.startswith('PY_') and name[3:] in renamed_variables:378item = ""379380elif 'PY_' + n in notdone:381found = False382383else:384item = str(done['PY_' + n])385else:386done[n] = item = ""387if found:388after = value[m.end():]389value = value[:m.start()] + item + after390if "$" in after:391notdone[name] = value392else:393try: value = int(value)394except ValueError:395done[name] = value.strip()396else:397done[name] = value398del notdone[name]399400if name.startswith('PY_') \401and name[3:] in renamed_variables:402403name = name[3:]404if name not in done:405done[name] = value406else:407# bogus variable reference; just drop it since we can't deal408del notdone[name]409410fp.close()411412# strip spurious spaces413for k, v in done.items():414if isinstance(v, str):415done[k] = v.strip()416417# save the results in the global dictionary418g.update(done)419return g420421422def expand_makefile_vars(s, vars):423"""Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in424'string' according to 'vars' (a dictionary mapping variable names to425values). Variables not present in 'vars' are silently expanded to the426empty string. The variable values in 'vars' should not contain further427variable expansions; if 'vars' is the output of 'parse_makefile()',428you're fine. Returns a variable-expanded version of 's'.429"""430431# This algorithm does multiple expansion, so if vars['foo'] contains432# "${bar}", it will expand ${foo} to ${bar}, and then expand433# ${bar}... and so forth. This is fine as long as 'vars' comes from434# 'parse_makefile()', which takes care of such expansions eagerly,435# according to make's variable expansion semantics.436437while True:438m = _findvar1_rx.search(s) or _findvar2_rx.search(s)439if m:440(beg, end) = m.span()441s = s[0:beg] + vars.get(m.group(1)) + s[end:]442else:443break444return s445446447_config_vars = None448449def _init_posix():450"""Initialize the module as appropriate for POSIX systems."""451# _sysconfigdata is generated at build time, see the sysconfig module452name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME',453'_sysconfigdata_{abi}_{platform}_{multiarch}'.format(454abi=sys.abiflags,455platform=sys.platform,456multiarch=getattr(sys.implementation, '_multiarch', ''),457))458try:459_temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)460except ImportError:461# Python 3.5 and pypy 7.3.1462_temp = __import__(463'_sysconfigdata', globals(), locals(), ['build_time_vars'], 0)464build_time_vars = _temp.build_time_vars465global _config_vars466_config_vars = {}467_config_vars.update(build_time_vars)468469470def _init_nt():471"""Initialize the module as appropriate for NT"""472g = {}473# set basic install directories474g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)475g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)476477# XXX hmmm.. a normal install puts include files here478g['INCLUDEPY'] = get_python_inc(plat_specific=0)479480g['EXT_SUFFIX'] = _imp.extension_suffixes()[0]481g['EXE'] = ".exe"482g['VERSION'] = get_python_version().replace(".", "")483g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable))484485global _config_vars486_config_vars = g487488489def get_config_vars(*args):490"""With no arguments, return a dictionary of all configuration491variables relevant for the current platform. Generally this includes492everything needed to build extensions and install both pure modules and493extensions. On Unix, this means every variable defined in Python's494installed Makefile; on Windows it's a much smaller set.495496With arguments, return a list of values that result from looking up497each argument in the configuration variable dictionary.498"""499global _config_vars500if _config_vars is None:501func = globals().get("_init_" + os.name)502if func:503func()504else:505_config_vars = {}506507# Normalized versions of prefix and exec_prefix are handy to have;508# in fact, these are the standard versions used most places in the509# Distutils.510_config_vars['prefix'] = PREFIX511_config_vars['exec_prefix'] = EXEC_PREFIX512513if not IS_PYPY:514# For backward compatibility, see issue19555515SO = _config_vars.get('EXT_SUFFIX')516if SO is not None:517_config_vars['SO'] = SO518519# Always convert srcdir to an absolute path520srcdir = _config_vars.get('srcdir', project_base)521if os.name == 'posix':522if python_build:523# If srcdir is a relative path (typically '.' or '..')524# then it should be interpreted relative to the directory525# containing Makefile.526base = os.path.dirname(get_makefile_filename())527srcdir = os.path.join(base, srcdir)528else:529# srcdir is not meaningful since the installation is530# spread about the filesystem. We choose the531# directory containing the Makefile since we know it532# exists.533srcdir = os.path.dirname(get_makefile_filename())534_config_vars['srcdir'] = os.path.abspath(os.path.normpath(srcdir))535536# Convert srcdir into an absolute path if it appears necessary.537# Normally it is relative to the build directory. However, during538# testing, for example, we might be running a non-installed python539# from a different directory.540if python_build and os.name == "posix":541base = project_base542if (not os.path.isabs(_config_vars['srcdir']) and543base != os.getcwd()):544# srcdir is relative and we are not in the same directory545# as the executable. Assume executable is in the build546# directory and make srcdir absolute.547srcdir = os.path.join(base, _config_vars['srcdir'])548_config_vars['srcdir'] = os.path.normpath(srcdir)549550# OS X platforms require special customization to handle551# multi-architecture, multi-os-version installers552if sys.platform == 'darwin':553import _osx_support554_osx_support.customize_config_vars(_config_vars)555556if args:557vals = []558for name in args:559vals.append(_config_vars.get(name))560return vals561else:562return _config_vars563564def get_config_var(name):565"""Return the value of a single variable using the dictionary566returned by 'get_config_vars()'. Equivalent to567get_config_vars().get(name)568"""569if name == 'SO':570import warnings571warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)572return get_config_vars().get(name)573574575