From 9de38bba372b1415c078d84246297a91b2055024 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 15 Oct 2020 07:44:08 +0200 Subject: [PATCH 01/24] Mark distutils.sysconfig as deprecated --- Lib/distutils/sysconfig.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 37feae5df72c93..da99f42a1d8bb3 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -13,9 +13,16 @@ import os import re import sys +import warnings from .errors import DistutilsPlatformError +warnings.warn( + 'the distutils.sysconfig module is deprecated, use sysconfig instead', + DeprecationWarning, + stacklevel=2 +) + # These are needed in a couple of spots, so just compute them once. PREFIX = os.path.normpath(sys.prefix) EXEC_PREFIX = os.path.normpath(sys.exec_prefix) From 2f73368cbd28dceb01f6bb0e0f5fd898d93fddb9 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 15 Oct 2020 08:03:33 +0200 Subject: [PATCH 02/24] Import global paths from sysconfig module --- Lib/distutils/sysconfig.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index da99f42a1d8bb3..e2858a849b846e 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -17,18 +17,17 @@ from .errors import DistutilsPlatformError +from sysconfig import _PREFIX as PREFIX +from sysconfig import _BASE_PREFIX as BASE_PREFIX +from sysconfig import _EXEC_PREFIX as EXEC_PREFIX +from sysconfig import _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX + warnings.warn( 'the distutils.sysconfig module is deprecated, use sysconfig instead', DeprecationWarning, stacklevel=2 ) -# These are needed in a couple of spots, so just compute them once. -PREFIX = os.path.normpath(sys.prefix) -EXEC_PREFIX = os.path.normpath(sys.exec_prefix) -BASE_PREFIX = os.path.normpath(sys.base_prefix) -BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix) - # Path to the base directory of the project. On Windows the binary may # live in project/PCbuild/win32 or project/PCbuild/amd64. # set for cross builds From 43d810eef6837fbf1957cc519ca99127ddc5418c Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 15 Oct 2020 09:35:11 +0200 Subject: [PATCH 03/24] Move some similar functions from distutils.sysconfig -> sysconfig --- Lib/distutils/sysconfig.py | 260 +++---------------------------------- Lib/sysconfig.py | 85 +++++++++++- 2 files changed, 99 insertions(+), 246 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index e2858a849b846e..60112ba5f62363 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -21,6 +21,17 @@ from sysconfig import _BASE_PREFIX as BASE_PREFIX from sysconfig import _EXEC_PREFIX as EXEC_PREFIX from sysconfig import _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX +from sysconfig import parse_config_h as sysconfig_parse_config_h +from sysconfig import _parse_makefile as sysconfig_parse_makefile + +from sysconfig import _is_python_source_dir +from sysconfig import _sys_home + +from sysconfig import expand_makefile_vars +from sysconfig import get_config_var +from sysconfig import get_python_version +from sysconfig import get_python_lib + warnings.warn( 'the distutils.sysconfig module is deprecated, use sysconfig instead', @@ -28,6 +39,16 @@ stacklevel=2 ) + +# Following functions are the same as in sysconfig but with different API +def parse_config_h(fp, g=None): + return sysconfig_parse_config_h(fp, vars=g) + + +def parse_makefile(fn, g=None): + return sysconfig_parse_makefile(fn, vars=g) + + # Path to the base directory of the project. On Windows the binary may # live in project/PCbuild/win32 or project/PCbuild/amd64. # set for cross builds @@ -42,17 +63,6 @@ project_base = os.getcwd() -# python_build: (Boolean) if true, we're either building Python or -# building an extension with an un-installed Python, so we use -# different (hard-wired) directories. -def _is_python_source_dir(d): - for fn in ("Setup", "Setup.local"): - if os.path.isfile(os.path.join(d, "Modules", fn)): - return True - return False - -_sys_home = getattr(sys, '_home', None) - if os.name == 'nt': def _fix_pcbuild(d): if d and os.path.normcase(d).startswith( @@ -82,13 +92,6 @@ def _python_build(): # this attribute, which is fine. pass -def get_python_version(): - """Return a string containing the major and minor Python version, - leaving off the patchlevel. Sample return values could be '1.5' - or '2.2'. - """ - return '%d.%d' % sys.version_info[:2] - def get_python_inc(plat_specific=0, prefix=None): """Return the directory containing installed Python header files. @@ -130,52 +133,6 @@ def get_python_inc(plat_specific=0, prefix=None): "on platform '%s'" % os.name) -def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): - """Return the directory containing the Python library (standard or - site additions). - - If 'plat_specific' is true, return the directory containing - platform-specific modules, i.e. any module from a non-pure-Python - module distribution; otherwise, return the platform-shared library - directory. If 'standard_lib' is true, return the directory - containing standard Python library modules; otherwise, return the - directory for site-specific modules. - - If 'prefix' is supplied, use it instead of sys.base_prefix or - sys.base_exec_prefix -- i.e., ignore 'plat_specific'. - """ - if prefix is None: - if standard_lib: - prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX - else: - prefix = plat_specific and EXEC_PREFIX or PREFIX - - if os.name == "posix": - if plat_specific or standard_lib: - # Platform-specific modules (any module from a non-pure-Python - # module distribution) or standard Python library modules. - libdir = sys.platlibdir - else: - # Pure Python - libdir = "lib" - libpython = os.path.join(prefix, libdir, - "python" + get_python_version()) - if standard_lib: - return libpython - else: - return os.path.join(libpython, "site-packages") - elif os.name == "nt": - if standard_lib: - return os.path.join(prefix, "Lib") - else: - return os.path.join(prefix, "Lib", "site-packages") - else: - raise DistutilsPlatformError( - "I don't know where Python installs its library " - "on platform '%s'" % os.name) - - - def customize_compiler(compiler): """Do any platform-specific customization of a CCompiler instance. @@ -273,172 +230,6 @@ def get_makefile_filename(): return os.path.join(lib_dir, config_file, 'Makefile') -def parse_config_h(fp, g=None): - """Parse a config.h-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - if g is None: - g = {} - define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") - undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") - # - while True: - line = fp.readline() - if not line: - break - m = define_rx.match(line) - if m: - n, v = m.group(1, 2) - try: v = int(v) - except ValueError: pass - g[n] = v - else: - m = undef_rx.match(line) - if m: - g[m.group(1)] = 0 - return g - - -# Regexes needed for parsing Makefile (and similar syntaxes, -# like old-style Setup files). -_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") -_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") -_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") - -def parse_makefile(fn, g=None): - """Parse a Makefile-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - from distutils.text_file import TextFile - fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape") - - if g is None: - g = {} - done = {} - notdone = {} - - while True: - line = fp.readline() - if line is None: # eof - break - m = _variable_rx.match(line) - if m: - n, v = m.group(1, 2) - v = v.strip() - # `$$' is a literal `$' in make - tmpv = v.replace('$$', '') - - if "$" in tmpv: - notdone[n] = v - else: - try: - v = int(v) - except ValueError: - # insert literal `$' - done[n] = v.replace('$$', '$') - else: - done[n] = v - - # Variables with a 'PY_' prefix in the makefile. These need to - # be made available without that prefix through sysconfig. - # Special care is needed to ensure that variable expansion works, even - # if the expansion uses the name without a prefix. - renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') - - # do variable interpolation here - while notdone: - for name in list(notdone): - value = notdone[name] - m = _findvar1_rx.search(value) or _findvar2_rx.search(value) - if m: - n = m.group(1) - found = True - if n in done: - item = str(done[n]) - elif n in notdone: - # get it on a subsequent round - found = False - elif n in os.environ: - # do it like make: fall back to environment - item = os.environ[n] - - elif n in renamed_variables: - if name.startswith('PY_') and name[3:] in renamed_variables: - item = "" - - elif 'PY_' + n in notdone: - found = False - - else: - item = str(done['PY_' + n]) - else: - done[n] = item = "" - if found: - after = value[m.end():] - value = value[:m.start()] + item + after - if "$" in after: - notdone[name] = value - else: - try: value = int(value) - except ValueError: - done[name] = value.strip() - else: - done[name] = value - del notdone[name] - - if name.startswith('PY_') \ - and name[3:] in renamed_variables: - - name = name[3:] - if name not in done: - done[name] = value - else: - # bogus variable reference; just drop it since we can't deal - del notdone[name] - - fp.close() - - # strip spurious spaces - for k, v in done.items(): - if isinstance(v, str): - done[k] = v.strip() - - # save the results in the global dictionary - g.update(done) - return g - - -def expand_makefile_vars(s, vars): - """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in - 'string' according to 'vars' (a dictionary mapping variable names to - values). Variables not present in 'vars' are silently expanded to the - empty string. The variable values in 'vars' should not contain further - variable expansions; if 'vars' is the output of 'parse_makefile()', - you're fine. Returns a variable-expanded version of 's'. - """ - - # This algorithm does multiple expansion, so if vars['foo'] contains - # "${bar}", it will expand ${foo} to ${bar}, and then expand - # ${bar}... and so forth. This is fine as long as 'vars' comes from - # 'parse_makefile()', which takes care of such expansions eagerly, - # according to make's variable expansion semantics. - - while True: - m = _findvar1_rx.search(s) or _findvar2_rx.search(s) - if m: - (beg, end) = m.span() - s = s[0:beg] + vars.get(m.group(1)) + s[end:] - else: - break - return s - - _config_vars = None def _init_posix(): @@ -550,12 +341,3 @@ def get_config_vars(*args): else: return _config_vars -def get_config_var(name): - """Return the value of a single variable using the dictionary - returned by 'get_config_vars()'. Equivalent to - get_config_vars().get(name) - """ - if name == 'SO': - import warnings - warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2) - return get_config_vars().get(name) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index d056d2c3381608..f42adb33d2a254 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -1,8 +1,10 @@ """Access to Python's configuration information.""" import os +import re import sys from os.path import pardir, realpath +from distutils.errors import DistutilsPlatformError __all__ = [ 'get_config_h_filename', @@ -130,6 +132,12 @@ def joinuser(*args): _CONFIG_VARS = None _USER_BASE = None +# Regexes needed for parsing Makefile (and similar syntaxes, +# like old-style Setup files). +_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") +_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") +_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") + def _safe_realpath(path): try: @@ -222,13 +230,6 @@ def _parse_makefile(filename, vars=None): optional dictionary is passed in as the second argument, it is used instead of a new dictionary. """ - # Regexes needed for parsing Makefile (and similar syntaxes, - # like old-style Setup files). - import re - _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") - _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") - _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") - if vars is None: vars = {} done = {} @@ -712,6 +713,76 @@ def get_python_version(): return _PY_VERSION_SHORT +def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): + """Return the directory containing the Python library (standard or + site additions). + + If 'plat_specific' is true, return the directory containing + platform-specific modules, i.e. any module from a non-pure-Python + module distribution; otherwise, return the platform-shared library + directory. If 'standard_lib' is true, return the directory + containing standard Python library modules; otherwise, return the + directory for site-specific modules. + + If 'prefix' is supplied, use it instead of sys.base_prefix or + sys.base_exec_prefix -- i.e., ignore 'plat_specific'. + """ + if prefix is None: + if standard_lib: + prefix = plat_specific and _BASE_EXEC_PREFIX or _BASE_PREFIX + else: + prefix = plat_specific and _EXEC_PREFIX or _PREFIX + + if os.name == "posix": + if plat_specific or standard_lib: + # Platform-specific modules (any module from a non-pure-Python + # module distribution) or standard Python library modules. + libdir = sys.platlibdir + else: + # Pure Python + libdir = "lib" + libpython = os.path.join(prefix, libdir, + "python" + get_python_version()) + if standard_lib: + return libpython + else: + return os.path.join(libpython, "site-packages") + elif os.name == "nt": + if standard_lib: + return os.path.join(prefix, "Lib") + else: + return os.path.join(prefix, "Lib", "site-packages") + else: + raise DistutilsPlatformError( + "I don't know where Python installs its library " + "on platform '%s'" % os.name) + + +def expand_makefile_vars(s, vars): + """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in + 'string' according to 'vars' (a dictionary mapping variable names to + values). Variables not present in 'vars' are silently expanded to the + empty string. The variable values in 'vars' should not contain further + variable expansions; if 'vars' is the output of 'parse_makefile()', + you're fine. Returns a variable-expanded version of 's'. + """ + + # This algorithm does multiple expansion, so if vars['foo'] contains + # "${bar}", it will expand ${foo} to ${bar}, and then expand + # ${bar}... and so forth. This is fine as long as 'vars' comes from + # 'parse_makefile()', which takes care of such expansions eagerly, + # according to make's variable expansion semantics. + + while True: + m = _findvar1_rx.search(s) or _findvar2_rx.search(s) + if m: + (beg, end) = m.span() + s = s[0:beg] + vars.get(m.group(1)) + s[end:] + else: + break + return s + + def _print_dict(title, data): for index, (key, value) in enumerate(sorted(data.items())): if index == 0: From 2ca4dfd87f9d100797136cb756adea88f20495b4 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 15 Oct 2020 10:53:10 +0200 Subject: [PATCH 04/24] Move the rest of global variables --- Lib/distutils/sysconfig.py | 96 +++++--------------------------------- Lib/sysconfig.py | 40 ++++++++++++++++ 2 files changed, 51 insertions(+), 85 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 60112ba5f62363..dc442d4e58b96f 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -15,23 +15,33 @@ import sys import warnings +from functools import partial + from .errors import DistutilsPlatformError from sysconfig import _PREFIX as PREFIX from sysconfig import _BASE_PREFIX as BASE_PREFIX from sysconfig import _EXEC_PREFIX as EXEC_PREFIX from sysconfig import _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX +from sysconfig import _PROJECT_BASE as project_base +from sysconfig import _PYTHON_BUILD as python_build +from sysconfig import _CONFIG_VARS as _config_vars from sysconfig import parse_config_h as sysconfig_parse_config_h from sysconfig import _parse_makefile as sysconfig_parse_makefile from sysconfig import _is_python_source_dir from sysconfig import _sys_home +from sysconfig import build_flags from sysconfig import expand_makefile_vars +from sysconfig import is_python_build from sysconfig import get_config_var +from sysconfig import get_python_inc from sysconfig import get_python_version from sysconfig import get_python_lib +if os.name == "nt": + from sysconfig import _fix_pcbuild warnings.warn( 'the distutils.sysconfig module is deprecated, use sysconfig instead', @@ -48,89 +58,7 @@ def parse_config_h(fp, g=None): def parse_makefile(fn, g=None): return sysconfig_parse_makefile(fn, vars=g) - -# Path to the base directory of the project. On Windows the binary may -# live in project/PCbuild/win32 or project/PCbuild/amd64. -# set for cross builds -if "_PYTHON_PROJECT_BASE" in os.environ: - project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"]) -else: - if sys.executable: - project_base = os.path.dirname(os.path.abspath(sys.executable)) - else: - # sys.executable can be empty if argv[0] has been changed and Python is - # unable to retrieve the real program name - project_base = os.getcwd() - - -if os.name == 'nt': - def _fix_pcbuild(d): - if d and os.path.normcase(d).startswith( - os.path.normcase(os.path.join(PREFIX, "PCbuild"))): - return PREFIX - return d - project_base = _fix_pcbuild(project_base) - _sys_home = _fix_pcbuild(_sys_home) - -def _python_build(): - if _sys_home: - return _is_python_source_dir(_sys_home) - return _is_python_source_dir(project_base) - -python_build = _python_build() - - -# Calculate the build qualifier flags if they are defined. Adding the flags -# to the include and lib directories only makes sense for an installation, not -# an in-source build. -build_flags = '' -try: - if not python_build: - build_flags = sys.abiflags -except AttributeError: - # It's not a configure-based build, so the sys module doesn't have - # this attribute, which is fine. - pass - - -def get_python_inc(plat_specific=0, prefix=None): - """Return the directory containing installed Python header files. - - If 'plat_specific' is false (the default), this is the path to the - non-platform-specific header files, i.e. Python.h and so on; - otherwise, this is the path to platform-specific header files - (namely pyconfig.h). - - If 'prefix' is supplied, use it instead of sys.base_prefix or - sys.base_exec_prefix -- i.e., ignore 'plat_specific'. - """ - if prefix is None: - prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX - if os.name == "posix": - if python_build: - # Assume the executable is in the build directory. The - # pyconfig.h file should be in the same directory. Since - # the build directory may not be the source directory, we - # must use "srcdir" from the makefile to find the "Include" - # directory. - if plat_specific: - return _sys_home or project_base - else: - incdir = os.path.join(get_config_var('srcdir'), 'Include') - return os.path.normpath(incdir) - python_dir = 'python' + get_python_version() + build_flags - return os.path.join(prefix, "include", python_dir) - elif os.name == "nt": - if python_build: - # Include both the include and PC dir to ensure we can find - # pyconfig.h - return (os.path.join(prefix, "include") + os.path.pathsep + - os.path.join(prefix, "PC")) - return os.path.join(prefix, "include") - else: - raise DistutilsPlatformError( - "I don't know where Python installs its C header files " - "on platform '%s'" % os.name) +_python_build = partial(is_python_build, check_home=True) def customize_compiler(compiler): @@ -230,8 +158,6 @@ def get_makefile_filename(): return os.path.join(lib_dir, config_file, 'Makefile') -_config_vars = None - def _init_posix(): """Initialize the module as appropriate for POSIX systems.""" # _sysconfigdata is generated at build time, see the sysconfig module diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index f42adb33d2a254..bdd5c6135662f6 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -713,6 +713,46 @@ def get_python_version(): return _PY_VERSION_SHORT +def get_python_inc(plat_specific=0, prefix=None): + """Return the directory containing installed Python header files. + + If 'plat_specific' is false (the default), this is the path to the + non-platform-specific header files, i.e. Python.h and so on; + otherwise, this is the path to platform-specific header files + (namely pyconfig.h). + + If 'prefix' is supplied, use it instead of sys.base_prefix or + sys.base_exec_prefix -- i.e., ignore 'plat_specific'. + """ + if prefix is None: + prefix = plat_specific and _BASE_EXEC_PREFIX or _BASE_PREFIX + if os.name == "posix": + if _PYTHON_BUILD: + # Assume the executable is in the build directory. The + # pyconfig.h file should be in the same directory. Since + # the build directory may not be the source directory, we + # must use "srcdir" from the makefile to find the "Include" + # directory. + if plat_specific: + return _sys_home or _PROJECT_BASE + else: + incdir = os.path.join(get_config_var('srcdir'), 'Include') + return os.path.normpath(incdir) + python_dir = 'python' + get_python_version() + build_flags + return os.path.join(prefix, "include", python_dir) + elif os.name == "nt": + if _PYTHON_BUILD: + # Include both the include and PC dir to ensure we can find + # pyconfig.h + return (os.path.join(prefix, "include") + os.path.pathsep + + os.path.join(prefix, "PC")) + return os.path.join(prefix, "include") + else: + raise DistutilsPlatformError( + "I don't know where Python installs its C header files " + "on platform '%s'" % os.name) + + def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): """Return the directory containing the Python library (standard or site additions). From 09f2617f843843b834faa8df07c2f919230666dc Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 15 Oct 2020 12:33:17 +0200 Subject: [PATCH 05/24] Move the rest of functions to sysconfig --- Lib/distutils/sysconfig.py | 216 ++----------------------------------- Lib/sysconfig.py | 73 +++++++++++++ 2 files changed, 81 insertions(+), 208 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index dc442d4e58b96f..273989bd32dfc2 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -26,16 +26,22 @@ from sysconfig import _PROJECT_BASE as project_base from sysconfig import _PYTHON_BUILD as python_build from sysconfig import _CONFIG_VARS as _config_vars +from sysconfig import _init_posix as sysconfig_init_posix from sysconfig import parse_config_h as sysconfig_parse_config_h from sysconfig import _parse_makefile as sysconfig_parse_makefile +from sysconfig import _init_non_posix from sysconfig import _is_python_source_dir from sysconfig import _sys_home from sysconfig import build_flags +from sysconfig import customize_compiler from sysconfig import expand_makefile_vars from sysconfig import is_python_build +from sysconfig import get_config_h_filename from sysconfig import get_config_var +from sysconfig import get_config_vars +from sysconfig import get_makefile_filename from sysconfig import get_python_inc from sysconfig import get_python_version from sysconfig import get_python_lib @@ -59,211 +65,5 @@ def parse_makefile(fn, g=None): return sysconfig_parse_makefile(fn, vars=g) _python_build = partial(is_python_build, check_home=True) - - -def customize_compiler(compiler): - """Do any platform-specific customization of a CCompiler instance. - - Mainly needed on Unix, so we can plug in the information that - varies across Unices and is stored in Python's Makefile. - """ - if compiler.compiler_type == "unix": - if sys.platform == "darwin": - # Perform first-time customization of compiler-related - # config vars on OS X now that we know we need a compiler. - # This is primarily to support Pythons from binary - # installers. The kind and paths to build tools on - # the user system may vary significantly from the system - # that Python itself was built on. Also the user OS - # version and build tools may not support the same set - # of CPU architectures for universal builds. - global _config_vars - # Use get_config_var() to ensure _config_vars is initialized. - if not get_config_var('CUSTOMIZED_OSX_COMPILER'): - import _osx_support - _osx_support.customize_compiler(_config_vars) - _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' - - (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ - get_config_vars('CC', 'CXX', 'CFLAGS', - 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') - - if 'CC' in os.environ: - newcc = os.environ['CC'] - if (sys.platform == 'darwin' - and 'LDSHARED' not in os.environ - and ldshared.startswith(cc)): - # On OS X, if CC is overridden, use that as the default - # command for LDSHARED as well - ldshared = newcc + ldshared[len(cc):] - cc = newcc - if 'CXX' in os.environ: - cxx = os.environ['CXX'] - if 'LDSHARED' in os.environ: - ldshared = os.environ['LDSHARED'] - if 'CPP' in os.environ: - cpp = os.environ['CPP'] - else: - cpp = cc + " -E" # not always - if 'LDFLAGS' in os.environ: - ldshared = ldshared + ' ' + os.environ['LDFLAGS'] - if 'CFLAGS' in os.environ: - cflags = cflags + ' ' + os.environ['CFLAGS'] - ldshared = ldshared + ' ' + os.environ['CFLAGS'] - if 'CPPFLAGS' in os.environ: - cpp = cpp + ' ' + os.environ['CPPFLAGS'] - cflags = cflags + ' ' + os.environ['CPPFLAGS'] - ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] - if 'AR' in os.environ: - ar = os.environ['AR'] - if 'ARFLAGS' in os.environ: - archiver = ar + ' ' + os.environ['ARFLAGS'] - else: - archiver = ar + ' ' + ar_flags - - cc_cmd = cc + ' ' + cflags - compiler.set_executables( - preprocessor=cpp, - compiler=cc_cmd, - compiler_so=cc_cmd + ' ' + ccshared, - compiler_cxx=cxx, - linker_so=ldshared, - linker_exe=cc, - archiver=archiver) - - compiler.shared_lib_extension = shlib_suffix - - -def get_config_h_filename(): - """Return full pathname of installed pyconfig.h file.""" - if python_build: - if os.name == "nt": - inc_dir = os.path.join(_sys_home or project_base, "PC") - else: - inc_dir = _sys_home or project_base - else: - inc_dir = get_python_inc(plat_specific=1) - - return os.path.join(inc_dir, 'pyconfig.h') - - -def get_makefile_filename(): - """Return full pathname of installed Makefile from the Python build.""" - if python_build: - return os.path.join(_sys_home or project_base, "Makefile") - lib_dir = get_python_lib(plat_specific=0, standard_lib=1) - config_file = 'config-{}{}'.format(get_python_version(), build_flags) - if hasattr(sys.implementation, '_multiarch'): - config_file += '-%s' % sys.implementation._multiarch - return os.path.join(lib_dir, config_file, 'Makefile') - - -def _init_posix(): - """Initialize the module as appropriate for POSIX systems.""" - # _sysconfigdata is generated at build time, see the sysconfig module - name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME', - '_sysconfigdata_{abi}_{platform}_{multiarch}'.format( - abi=sys.abiflags, - platform=sys.platform, - multiarch=getattr(sys.implementation, '_multiarch', ''), - )) - _temp = __import__(name, globals(), locals(), ['build_time_vars'], 0) - build_time_vars = _temp.build_time_vars - global _config_vars - _config_vars = {} - _config_vars.update(build_time_vars) - - -def _init_nt(): - """Initialize the module as appropriate for NT""" - g = {} - # set basic install directories - g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) - g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) - - # XXX hmmm.. a normal install puts include files here - g['INCLUDEPY'] = get_python_inc(plat_specific=0) - - g['EXT_SUFFIX'] = _imp.extension_suffixes()[0] - g['EXE'] = ".exe" - g['VERSION'] = get_python_version().replace(".", "") - g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable)) - - global _config_vars - _config_vars = g - - -def get_config_vars(*args): - """With no arguments, return a dictionary of all configuration - variables relevant for the current platform. Generally this includes - everything needed to build extensions and install both pure modules and - extensions. On Unix, this means every variable defined in Python's - installed Makefile; on Windows it's a much smaller set. - - With arguments, return a list of values that result from looking up - each argument in the configuration variable dictionary. - """ - global _config_vars - if _config_vars is None: - func = globals().get("_init_" + os.name) - if func: - func() - else: - _config_vars = {} - - # Normalized versions of prefix and exec_prefix are handy to have; - # in fact, these are the standard versions used most places in the - # Distutils. - _config_vars['prefix'] = PREFIX - _config_vars['exec_prefix'] = EXEC_PREFIX - - # For backward compatibility, see issue19555 - SO = _config_vars.get('EXT_SUFFIX') - if SO is not None: - _config_vars['SO'] = SO - - # Always convert srcdir to an absolute path - srcdir = _config_vars.get('srcdir', project_base) - if os.name == 'posix': - if python_build: - # If srcdir is a relative path (typically '.' or '..') - # then it should be interpreted relative to the directory - # containing Makefile. - base = os.path.dirname(get_makefile_filename()) - srcdir = os.path.join(base, srcdir) - else: - # srcdir is not meaningful since the installation is - # spread about the filesystem. We choose the - # directory containing the Makefile since we know it - # exists. - srcdir = os.path.dirname(get_makefile_filename()) - _config_vars['srcdir'] = os.path.abspath(os.path.normpath(srcdir)) - - # Convert srcdir into an absolute path if it appears necessary. - # Normally it is relative to the build directory. However, during - # testing, for example, we might be running a non-installed python - # from a different directory. - if python_build and os.name == "posix": - base = project_base - if (not os.path.isabs(_config_vars['srcdir']) and - base != os.getcwd()): - # srcdir is relative and we are not in the same directory - # as the executable. Assume executable is in the build - # directory and make srcdir absolute. - srcdir = os.path.join(base, _config_vars['srcdir']) - _config_vars['srcdir'] = os.path.normpath(srcdir) - - # OS X platforms require special customization to handle - # multi-architecture, multi-os-version installers - if sys.platform == 'darwin': - import _osx_support - _osx_support.customize_config_vars(_config_vars) - - if args: - vals = [] - for name in args: - vals.append(_config_vars.get(name)) - return vals - else: - return _config_vars - +_init_posix = partial(sysconfig_init_posix, _config_vars) +_init_nt = partial(_init_non_posix, _config_vars) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index bdd5c6135662f6..83e3212487b7c7 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -823,6 +823,79 @@ def expand_makefile_vars(s, vars): return s +def customize_compiler(compiler): + """Do any platform-specific customization of a CCompiler instance. + + Mainly needed on Unix, so we can plug in the information that + varies across Unices and is stored in Python's Makefile. + """ + if compiler.compiler_type == "unix": + if sys.platform == "darwin": + # Perform first-time customization of compiler-related + # config vars on OS X now that we know we need a compiler. + # This is primarily to support Pythons from binary + # installers. The kind and paths to build tools on + # the user system may vary significantly from the system + # that Python itself was built on. Also the user OS + # version and build tools may not support the same set + # of CPU architectures for universal builds. + global _CONFIG_VARS + # Use get_config_var() to ensure _CONFIG_VARS is initialized. + if not get_config_var('CUSTOMIZED_OSX_COMPILER'): + import _osx_support + _osx_support.customize_compiler(_CONFIG_VARS) + _CONFIG_VARS['CUSTOMIZED_OSX_COMPILER'] = 'True' + + (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ + get_config_vars('CC', 'CXX', 'CFLAGS', + 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') + + if 'CC' in os.environ: + newcc = os.environ['CC'] + if (sys.platform == 'darwin' + and 'LDSHARED' not in os.environ + and ldshared.startswith(cc)): + # On OS X, if CC is overridden, use that as the default + # command for LDSHARED as well + ldshared = newcc + ldshared[len(cc):] + cc = newcc + if 'CXX' in os.environ: + cxx = os.environ['CXX'] + if 'LDSHARED' in os.environ: + ldshared = os.environ['LDSHARED'] + if 'CPP' in os.environ: + cpp = os.environ['CPP'] + else: + cpp = cc + " -E" # not always + if 'LDFLAGS' in os.environ: + ldshared = ldshared + ' ' + os.environ['LDFLAGS'] + if 'CFLAGS' in os.environ: + cflags = cflags + ' ' + os.environ['CFLAGS'] + ldshared = ldshared + ' ' + os.environ['CFLAGS'] + if 'CPPFLAGS' in os.environ: + cpp = cpp + ' ' + os.environ['CPPFLAGS'] + cflags = cflags + ' ' + os.environ['CPPFLAGS'] + ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] + if 'AR' in os.environ: + ar = os.environ['AR'] + if 'ARFLAGS' in os.environ: + archiver = ar + ' ' + os.environ['ARFLAGS'] + else: + archiver = ar + ' ' + ar_flags + + cc_cmd = cc + ' ' + cflags + compiler.set_executables( + preprocessor=cpp, + compiler=cc_cmd, + compiler_so=cc_cmd + ' ' + ccshared, + compiler_cxx=cxx, + linker_so=ldshared, + linker_exe=cc, + archiver=archiver) + + compiler.shared_lib_extension = shlib_suffix + + def _print_dict(title, data): for index, (key, value) in enumerate(sorted(data.items())): if index == 0: From 24e0584bf56ca11637e0e77f85dec9d33099956a Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 16 Oct 2020 07:39:11 +0200 Subject: [PATCH 06/24] Import regexes used in tests --- Lib/distutils/sysconfig.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 273989bd32dfc2..3ddce70d6d3a72 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -34,6 +34,10 @@ from sysconfig import _is_python_source_dir from sysconfig import _sys_home +from sysconfig import _variable_rx +from sysconfig import _findvar1_rx +from sysconfig import _findvar2_rx + from sysconfig import build_flags from sysconfig import customize_compiler from sysconfig import expand_makefile_vars From b9ee651258c00d17543521a13796a123a0d53e08 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 16 Oct 2020 07:47:34 +0200 Subject: [PATCH 07/24] Implement compatibility option for parse_makefile --- Lib/distutils/sysconfig.py | 2 +- Lib/sysconfig.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 3ddce70d6d3a72..22fc067a38314a 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -66,7 +66,7 @@ def parse_config_h(fp, g=None): def parse_makefile(fn, g=None): - return sysconfig_parse_makefile(fn, vars=g) + return sysconfig_parse_makefile(fn, vars=g, distutils_compat=True) _python_build = partial(is_python_build, check_home=True) _init_posix = partial(sysconfig_init_posix, _config_vars) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 83e3212487b7c7..afddfb31460a69 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -223,7 +223,7 @@ def _get_default_scheme(): -def _parse_makefile(filename, vars=None): +def _parse_makefile(filename, vars=None, distutils_compat=False): """Parse a Makefile-style file. A dictionary containing name/value pairs is returned. If an @@ -331,9 +331,12 @@ def _parse_makefile(filename, vars=None): done[name] = value else: + # The same function in distutils would not add + # unresolved variable to the done dictionary + if not distutils_compat: + done[name] = value # bogus variable reference (e.g. "prefix=$/opt/python"); # just drop it since we can't deal - done[name] = value variables.remove(name) # strip spurious spaces From 12f92cf4861749f4b83231f60926af1983d89a50 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Mon, 19 Oct 2020 12:42:08 +0200 Subject: [PATCH 08/24] Do not use assignment in teardown to not lose reference to global dict --- Lib/distutils/tests/test_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/distutils/tests/test_util.py b/Lib/distutils/tests/test_util.py index bf0d4333f9aeaa..d4a01c6e91ce2b 100644 --- a/Lib/distutils/tests/test_util.py +++ b/Lib/distutils/tests/test_util.py @@ -54,7 +54,8 @@ def tearDown(self): os.uname = self.uname else: del os.uname - sysconfig._config_vars = copy(self._config_vars) + sysconfig._config_vars.clear() + sysconfig._config_vars.update(self._config_vars) super(UtilTestCase, self).tearDown() def _set_uname(self, uname): From 7b9b0c118999b0be248d5ab98e0f4b5c5751e659 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 20 Oct 2020 09:33:23 +0200 Subject: [PATCH 09/24] Ignore DeprecationWarning in pip code in ensurepip module --- Lib/ensurepip/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 74530706be5c70..0f1df6e8a839d1 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -90,7 +90,8 @@ def _run_pip(args, additional_paths=None): sys.argv[1:] = {args} runpy.run_module("pip", run_name="__main__", alter_sys=True) """ - return subprocess.run([sys.executable, "-c", code], check=True).returncode + return subprocess.run([sys.executable, '-W', 'ignore::DeprecationWarning', + "-c", code], check=True).returncode def version(): From 6f5aa4f84229d032afab7488d000f1e07e46b230 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 20 Oct 2020 12:02:22 +0200 Subject: [PATCH 10/24] Improve setUp/tearDown of UnixCCompilerTestCase --- Lib/distutils/tests/test_unixccompiler.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/distutils/tests/test_unixccompiler.py b/Lib/distutils/tests/test_unixccompiler.py index eefe4ba40291eb..24725ead1194ce 100644 --- a/Lib/distutils/tests/test_unixccompiler.py +++ b/Lib/distutils/tests/test_unixccompiler.py @@ -12,6 +12,7 @@ class UnixCCompilerTestCase(unittest.TestCase): def setUp(self): self._backup_platform = sys.platform self._backup_get_config_var = sysconfig.get_config_var + self._backup_config_vars = dict(sysconfig._config_vars) class CompilerWrapper(UnixCCompiler): def rpath_foo(self): return self.runtime_library_dir_option('/foo') @@ -20,6 +21,8 @@ def rpath_foo(self): def tearDown(self): sys.platform = self._backup_platform sysconfig.get_config_var = self._backup_get_config_var + sysconfig._config_vars.clear() + sysconfig._config_vars.update(self._backup_config_vars) @unittest.skipIf(sys.platform == 'win32', "can't test on Windows") def test_runtime_libdir_option(self): From fca8adc5b0bfb7f1f24f1fd9ca7805c4f35bd6b3 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Wed, 21 Oct 2020 14:10:30 +0200 Subject: [PATCH 11/24] Improve or create setUp/tearDown methods for tests where sysconfig._CONFIG_VARS might be modified --- Lib/distutils/tests/test_build_clib.py | 10 ++++++++++ Lib/distutils/tests/test_build_ext.py | 3 +++ Lib/distutils/tests/test_config_cmd.py | 4 ++++ Lib/distutils/tests/test_install.py | 9 +++++++++ Lib/test/test_peg_generator/test_c_parser.py | 3 +++ 5 files changed, 29 insertions(+) diff --git a/Lib/distutils/tests/test_build_clib.py b/Lib/distutils/tests/test_build_clib.py index abd8313770ef7a..19e012a58ce8cb 100644 --- a/Lib/distutils/tests/test_build_clib.py +++ b/Lib/distutils/tests/test_build_clib.py @@ -2,6 +2,7 @@ import unittest import os import sys +import sysconfig from test.support import run_unittest, missing_compiler_executable @@ -13,6 +14,15 @@ class BuildCLibTestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): + def setUp(self): + super().setUp() + self._backup_CONFIG_VARS = dict(sysconfig._CONFIG_VARS) + + def tearDown(self): + super().tearDown() + sysconfig._CONFIG_VARS.clear() + sysconfig._CONFIG_VARS.update(self._backup_CONFIG_VARS) + def test_check_library_dist(self): pkg_dir, dist = self.create_dist() cmd = build_clib(dist) diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 90f7bb066917bc..8e7364d2a2cb5f 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -35,6 +35,7 @@ def setUp(self): site.USER_BASE = self.mkdtemp() from distutils.command import build_ext build_ext.USER_BASE = site.USER_BASE + self.old_config_vars = dict(sysconfig._config_vars) # bpo-30132: On Windows, a .pdb file may be created in the current # working directory. Create a temporary working directory to cleanup @@ -48,6 +49,8 @@ def tearDown(self): site.USER_BASE = self.old_user_base from distutils.command import build_ext build_ext.USER_BASE = self.old_user_base + sysconfig._config_vars.clear() + sysconfig._config_vars.update(self.old_config_vars) super(BuildExtTestCase, self).tearDown() def build_ext(self, *args, **kwargs): diff --git a/Lib/distutils/tests/test_config_cmd.py b/Lib/distutils/tests/test_config_cmd.py index 9aeab07b468361..0127ba71fc4bc4 100644 --- a/Lib/distutils/tests/test_config_cmd.py +++ b/Lib/distutils/tests/test_config_cmd.py @@ -2,6 +2,7 @@ import unittest import os import sys +import sysconfig from test.support import run_unittest, missing_compiler_executable from distutils.command.config import dump_file, config @@ -21,9 +22,12 @@ def setUp(self): self._logs = [] self.old_log = log.info log.info = self._info + self.old_config_vars = dict(sysconfig._CONFIG_VARS) def tearDown(self): log.info = self.old_log + sysconfig._CONFIG_VARS.clear() + sysconfig._CONFIG_VARS.update(self.old_config_vars) super(ConfigTestCase, self).tearDown() def test_dump_file(self): diff --git a/Lib/distutils/tests/test_install.py b/Lib/distutils/tests/test_install.py index 21a7b7c85c49da..0632024b3585ce 100644 --- a/Lib/distutils/tests/test_install.py +++ b/Lib/distutils/tests/test_install.py @@ -29,6 +29,15 @@ class InstallTestCase(support.TempdirManager, support.LoggingSilencer, unittest.TestCase): + def setUp(self): + super().setUp() + self._backup_config_vars = dict(sysconfig._config_vars) + + def tearDown(self): + super().tearDown() + sysconfig._config_vars.clear() + sysconfig._config_vars.update(self._backup_config_vars) + def test_home_installation_scheme(self): # This ensure two things: # - that --home generates the desired set of directory names diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index b7e80f0d351a26..3852cfbc477b6b 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -70,6 +70,7 @@ def test_parse(self): class TestCParser(TempdirManager, unittest.TestCase): def setUp(self): + self._backup_config_vars = dict(sysconfig._CONFIG_VARS) cmd = support.missing_compiler_executable() if cmd is not None: self.skipTest("The %r command is not found" % cmd) @@ -81,6 +82,8 @@ def setUp(self): def tearDown(self): super(TestCParser, self).tearDown() + sysconfig._CONFIG_VARS.clear() + sysconfig._CONFIG_VARS.update(self._backup_config_vars) def build_extension(self, grammar_source): grammar = parse_string(grammar_source, GrammarParser) From 318428db0ffaa69f7210f30adb42f824ca576e39 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 23 Oct 2020 12:10:59 +0200 Subject: [PATCH 12/24] Rename `distutils_compat` to `keep_unresolved` and reverse the logic --- Lib/distutils/sysconfig.py | 2 +- Lib/sysconfig.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 22fc067a38314a..b0b843f6703e1e 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -66,7 +66,7 @@ def parse_config_h(fp, g=None): def parse_makefile(fn, g=None): - return sysconfig_parse_makefile(fn, vars=g, distutils_compat=True) + return sysconfig_parse_makefile(fn, vars=g, keep_unresolved=False) _python_build = partial(is_python_build, check_home=True) _init_posix = partial(sysconfig_init_posix, _config_vars) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index afddfb31460a69..82b5861634f12b 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -223,7 +223,7 @@ def _get_default_scheme(): -def _parse_makefile(filename, vars=None, distutils_compat=False): +def _parse_makefile(filename, vars=None, keep_unresolved=True): """Parse a Makefile-style file. A dictionary containing name/value pairs is returned. If an @@ -331,9 +331,9 @@ def _parse_makefile(filename, vars=None, distutils_compat=False): done[name] = value else: - # The same function in distutils would not add - # unresolved variable to the done dictionary - if not distutils_compat: + # Adds unresolved variables to the done dict. + # This is disabled when called from distutils.sysconfig + if keep_unresolved: done[name] = value # bogus variable reference (e.g. "prefix=$/opt/python"); # just drop it since we can't deal From 6136978d0870befce5a8d66f9c2f366751f1d66c Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 23 Oct 2020 12:23:01 +0200 Subject: [PATCH 13/24] Merge all import from sysconfig to one statement --- Lib/distutils/sysconfig.py | 55 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index b0b843f6703e1e..6f30f059fb9df7 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -19,36 +19,37 @@ from .errors import DistutilsPlatformError -from sysconfig import _PREFIX as PREFIX -from sysconfig import _BASE_PREFIX as BASE_PREFIX -from sysconfig import _EXEC_PREFIX as EXEC_PREFIX -from sysconfig import _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX -from sysconfig import _PROJECT_BASE as project_base -from sysconfig import _PYTHON_BUILD as python_build -from sysconfig import _CONFIG_VARS as _config_vars -from sysconfig import _init_posix as sysconfig_init_posix -from sysconfig import parse_config_h as sysconfig_parse_config_h -from sysconfig import _parse_makefile as sysconfig_parse_makefile +from sysconfig import ( + _PREFIX as PREFIX, + _BASE_PREFIX as BASE_PREFIX, + _EXEC_PREFIX as EXEC_PREFIX, + _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX, + _PROJECT_BASE as project_base, + _PYTHON_BUILD as python_build, + _CONFIG_VARS as _config_vars, + _init_posix as sysconfig_init_posix, + parse_config_h as sysconfig_parse_config_h, + _parse_makefile as sysconfig_parse_makefile, -from sysconfig import _init_non_posix -from sysconfig import _is_python_source_dir -from sysconfig import _sys_home + _init_non_posix, + _is_python_source_dir, + _sys_home, -from sysconfig import _variable_rx -from sysconfig import _findvar1_rx -from sysconfig import _findvar2_rx + _variable_rx, + _findvar1_rx, + _findvar2_rx, -from sysconfig import build_flags -from sysconfig import customize_compiler -from sysconfig import expand_makefile_vars -from sysconfig import is_python_build -from sysconfig import get_config_h_filename -from sysconfig import get_config_var -from sysconfig import get_config_vars -from sysconfig import get_makefile_filename -from sysconfig import get_python_inc -from sysconfig import get_python_version -from sysconfig import get_python_lib + customize_compiler, + expand_makefile_vars, + is_python_build, + get_config_h_filename, + get_config_var, + get_config_vars, + get_makefile_filename, + get_python_inc, + get_python_version, + get_python_lib, +) if os.name == "nt": from sysconfig import _fix_pcbuild From e635dbdd75d32cb71fd44f5563f9aff93c864262 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 23 Oct 2020 12:31:51 +0200 Subject: [PATCH 14/24] Allow import of sysconfig when re module is not available --- Lib/sysconfig.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 82b5861634f12b..cefa8b07697bfa 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -1,7 +1,6 @@ """Access to Python's configuration information.""" import os -import re import sys from os.path import pardir, realpath from distutils.errors import DistutilsPlatformError @@ -134,9 +133,13 @@ def joinuser(*args): # Regexes needed for parsing Makefile (and similar syntaxes, # like old-style Setup files). -_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") -_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") -_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") +try: + import re + _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") + _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") + _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") +except ImportError: + pass def _safe_realpath(path): From d8a8cf02ef965014f013aee73e72bd308fb9ba8d Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 23 Oct 2020 13:13:57 +0200 Subject: [PATCH 15/24] Add a TODO comment about PEP 632 --- Lib/test/support/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 5a45d78be91663..80f3a04fcc6180 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1667,6 +1667,7 @@ def missing_compiler_executable(cmd_names=[]): missing. """ + # TODO (PEP 632): alternate check without using distutils from distutils import ccompiler, sysconfig, spawn, errors compiler = ccompiler.new_compiler() sysconfig.customize_compiler(compiler) From e317db5a09f01861d8deb33023aaf3dcf59dad41 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 23 Oct 2020 13:38:24 +0200 Subject: [PATCH 16/24] Mark distutils.sysconfig as deprecated in docs --- Doc/distutils/apiref.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst index 6c69c11ccaa9a8..3b1d73f962fc43 100644 --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -1452,6 +1452,8 @@ name. .. module:: distutils.sysconfig :synopsis: Low-level access to configuration information of the Python interpreter. +.. deprecated:: 3.10 + :mod:`distutils.sysconfig` has been merged to :mod:`sysconfig`. .. moduleauthor:: Fred L. Drake, Jr. .. moduleauthor:: Greg Ward .. sectionauthor:: Fred L. Drake, Jr. From 17206f066c9aedbfc1e6cfe889936472f590891d Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 23 Oct 2020 13:38:43 +0200 Subject: [PATCH 17/24] Copy docs for get_python_inc and get_python_lib from distutils.sysconfig to sysconfig --- Doc/library/sysconfig.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index c9306e9bf9de16..4f0a65dd4c9665 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -224,6 +224,30 @@ Other functions Return the path of :file:`Makefile`. +The following functions have been moved here from :mod:`distutils.sysconfig` +when this module has been deprecated. + +.. function:: get_python_inc([plat_specific[, prefix]]) + + Return the directory for either the general or platform-dependent C include + files. If *plat_specific* is true, the platform-dependent include directory is + returned; if false or omitted, the platform-independent directory is returned. + If *prefix* is given, it is used as either the prefix instead of + :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if + *plat_specific* is true. + + +.. function:: get_python_lib([plat_specific[, standard_lib[, prefix]]]) + + Return the directory for either the general or platform-dependent library + installation. If *plat_specific* is true, the platform-dependent include + directory is returned; if false or omitted, the platform-independent directory + is returned. If *prefix* is given, it is used as either the prefix instead of + :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if + *plat_specific* is true. If *standard_lib* is true, the directory for the + standard library is returned rather than the directory for the installation of + third-party extensions. + Using :mod:`sysconfig` as a script ---------------------------------- From 04ef7af729ccc31a111728920695962ab5431d4b Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Sat, 24 Oct 2020 07:36:23 +0200 Subject: [PATCH 18/24] Move customize_compiler back to distutils.sysconfig as it'll be removedtogether with the module. --- Lib/distutils/sysconfig.py | 75 +++++++++++++++++++++++++++++++++++++- Lib/sysconfig.py | 73 ------------------------------------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 6f30f059fb9df7..1ce2d0045505ac 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -39,7 +39,6 @@ _findvar1_rx, _findvar2_rx, - customize_compiler, expand_makefile_vars, is_python_build, get_config_h_filename, @@ -72,3 +71,77 @@ def parse_makefile(fn, g=None): _python_build = partial(is_python_build, check_home=True) _init_posix = partial(sysconfig_init_posix, _config_vars) _init_nt = partial(_init_non_posix, _config_vars) + + +# customize_compiler is deprecated and won't be moved to another module +def customize_compiler(compiler): + """Do any platform-specific customization of a CCompiler instance. + + Mainly needed on Unix, so we can plug in the information that + varies across Unices and is stored in Python's Makefile. + """ + if compiler.compiler_type == "unix": + if sys.platform == "darwin": + # Perform first-time customization of compiler-related + # config vars on OS X now that we know we need a compiler. + # This is primarily to support Pythons from binary + # installers. The kind and paths to build tools on + # the user system may vary significantly from the system + # that Python itself was built on. Also the user OS + # version and build tools may not support the same set + # of CPU architectures for universal builds. + global _config_vars + # Use get_config_var() to ensure _config_vars is initialized. + if not get_config_var('CUSTOMIZED_OSX_COMPILER'): + import _osx_support + _osx_support.customize_compiler(_config_vars) + _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' + + (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ + get_config_vars('CC', 'CXX', 'CFLAGS', + 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') + + if 'CC' in os.environ: + newcc = os.environ['CC'] + if (sys.platform == 'darwin' + and 'LDSHARED' not in os.environ + and ldshared.startswith(cc)): + # On OS X, if CC is overridden, use that as the default + # command for LDSHARED as well + ldshared = newcc + ldshared[len(cc):] + cc = newcc + if 'CXX' in os.environ: + cxx = os.environ['CXX'] + if 'LDSHARED' in os.environ: + ldshared = os.environ['LDSHARED'] + if 'CPP' in os.environ: + cpp = os.environ['CPP'] + else: + cpp = cc + " -E" # not always + if 'LDFLAGS' in os.environ: + ldshared = ldshared + ' ' + os.environ['LDFLAGS'] + if 'CFLAGS' in os.environ: + cflags = cflags + ' ' + os.environ['CFLAGS'] + ldshared = ldshared + ' ' + os.environ['CFLAGS'] + if 'CPPFLAGS' in os.environ: + cpp = cpp + ' ' + os.environ['CPPFLAGS'] + cflags = cflags + ' ' + os.environ['CPPFLAGS'] + ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] + if 'AR' in os.environ: + ar = os.environ['AR'] + if 'ARFLAGS' in os.environ: + archiver = ar + ' ' + os.environ['ARFLAGS'] + else: + archiver = ar + ' ' + ar_flags + + cc_cmd = cc + ' ' + cflags + compiler.set_executables( + preprocessor=cpp, + compiler=cc_cmd, + compiler_so=cc_cmd + ' ' + ccshared, + compiler_cxx=cxx, + linker_so=ldshared, + linker_exe=cc, + archiver=archiver) + + compiler.shared_lib_extension = shlib_suffix diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index cefa8b07697bfa..4270b9ada2bac8 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -829,79 +829,6 @@ def expand_makefile_vars(s, vars): return s -def customize_compiler(compiler): - """Do any platform-specific customization of a CCompiler instance. - - Mainly needed on Unix, so we can plug in the information that - varies across Unices and is stored in Python's Makefile. - """ - if compiler.compiler_type == "unix": - if sys.platform == "darwin": - # Perform first-time customization of compiler-related - # config vars on OS X now that we know we need a compiler. - # This is primarily to support Pythons from binary - # installers. The kind and paths to build tools on - # the user system may vary significantly from the system - # that Python itself was built on. Also the user OS - # version and build tools may not support the same set - # of CPU architectures for universal builds. - global _CONFIG_VARS - # Use get_config_var() to ensure _CONFIG_VARS is initialized. - if not get_config_var('CUSTOMIZED_OSX_COMPILER'): - import _osx_support - _osx_support.customize_compiler(_CONFIG_VARS) - _CONFIG_VARS['CUSTOMIZED_OSX_COMPILER'] = 'True' - - (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ - get_config_vars('CC', 'CXX', 'CFLAGS', - 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') - - if 'CC' in os.environ: - newcc = os.environ['CC'] - if (sys.platform == 'darwin' - and 'LDSHARED' not in os.environ - and ldshared.startswith(cc)): - # On OS X, if CC is overridden, use that as the default - # command for LDSHARED as well - ldshared = newcc + ldshared[len(cc):] - cc = newcc - if 'CXX' in os.environ: - cxx = os.environ['CXX'] - if 'LDSHARED' in os.environ: - ldshared = os.environ['LDSHARED'] - if 'CPP' in os.environ: - cpp = os.environ['CPP'] - else: - cpp = cc + " -E" # not always - if 'LDFLAGS' in os.environ: - ldshared = ldshared + ' ' + os.environ['LDFLAGS'] - if 'CFLAGS' in os.environ: - cflags = cflags + ' ' + os.environ['CFLAGS'] - ldshared = ldshared + ' ' + os.environ['CFLAGS'] - if 'CPPFLAGS' in os.environ: - cpp = cpp + ' ' + os.environ['CPPFLAGS'] - cflags = cflags + ' ' + os.environ['CPPFLAGS'] - ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] - if 'AR' in os.environ: - ar = os.environ['AR'] - if 'ARFLAGS' in os.environ: - archiver = ar + ' ' + os.environ['ARFLAGS'] - else: - archiver = ar + ' ' + ar_flags - - cc_cmd = cc + ' ' + cflags - compiler.set_executables( - preprocessor=cpp, - compiler=cc_cmd, - compiler_so=cc_cmd + ' ' + ccshared, - compiler_cxx=cxx, - linker_so=ldshared, - linker_exe=cc, - archiver=archiver) - - compiler.shared_lib_extension = shlib_suffix - - def _print_dict(title, data): for index, (key, value) in enumerate(sorted(data.items())): if index == 0: From 60152550f32ca0fbbb09c2bde4f7522f6bc79d7b Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Tue, 3 Nov 2020 14:24:33 +0100 Subject: [PATCH 19/24] Fix import of not-yet-initialized _CONFIG_VARS --- Lib/distutils/sysconfig.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 1ce2d0045505ac..4a987b1732416b 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -26,7 +26,6 @@ _BASE_EXEC_PREFIX as BASE_EXEC_PREFIX, _PROJECT_BASE as project_base, _PYTHON_BUILD as python_build, - _CONFIG_VARS as _config_vars, _init_posix as sysconfig_init_posix, parse_config_h as sysconfig_parse_config_h, _parse_makefile as sysconfig_parse_makefile, @@ -50,6 +49,12 @@ get_python_lib, ) +# This is better than +# from sysconfig import _CONFIG_VARS as _config_vars +# because it makes sure that the global dictionary is initialized +# which might not be true in the time of import. +_config_vars = get_config_vars() + if os.name == "nt": from sysconfig import _fix_pcbuild @@ -90,9 +95,7 @@ def customize_compiler(compiler): # that Python itself was built on. Also the user OS # version and build tools may not support the same set # of CPU architectures for universal builds. - global _config_vars - # Use get_config_var() to ensure _config_vars is initialized. - if not get_config_var('CUSTOMIZED_OSX_COMPILER'): + if not _config_vars.get('CUSTOMIZED_OSX_COMPILER'): import _osx_support _osx_support.customize_compiler(_config_vars) _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' From abc310bf67b268b09d207fc924f296b61ccc3240 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Thu, 5 Nov 2020 10:42:55 +0100 Subject: [PATCH 20/24] Switch global vars from regex objects to raw strings and import re only when needed --- Lib/distutils/extension.py | 3 ++- Lib/sysconfig.py | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Lib/distutils/extension.py b/Lib/distutils/extension.py index c507da360aa3d9..e85032ece8916f 100644 --- a/Lib/distutils/extension.py +++ b/Lib/distutils/extension.py @@ -4,6 +4,7 @@ modules in setup scripts.""" import os +import re import warnings # This class is really only used by the "build_ext" command, so it might @@ -161,7 +162,7 @@ def read_setup_file(filename): line = file.readline() if line is None: # eof break - if _variable_rx.match(line): # VAR=VALUE, handled in first pass + if re.match(_variable_rx, line): # VAR=VALUE, handled in first pass continue if line[0] == line[-1] == "*": diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 4270b9ada2bac8..449b225c80ebc2 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -133,13 +133,9 @@ def joinuser(*args): # Regexes needed for parsing Makefile (and similar syntaxes, # like old-style Setup files). -try: - import re - _variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") - _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") - _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") -except ImportError: - pass +_variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)" +_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)" +_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}" def _safe_realpath(path): @@ -233,6 +229,8 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True): optional dictionary is passed in as the second argument, it is used instead of a new dictionary. """ + import re + if vars is None: vars = {} done = {} @@ -245,7 +243,7 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True): for line in lines: if line.startswith('#') or line.strip() == '': continue - m = _variable_rx.match(line) + m = re.match(_variable_rx, line) if m: n, v = m.group(1, 2) v = v.strip() @@ -278,8 +276,8 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True): while len(variables) > 0: for name in tuple(variables): value = notdone[name] - m1 = _findvar1_rx.search(value) - m2 = _findvar2_rx.search(value) + m1 = re.search(_findvar1_rx, value) + m2 = re.search(_findvar2_rx, value) if m1 and m2: m = m1 if m1.start() < m2.start() else m2 else: @@ -812,6 +810,7 @@ def expand_makefile_vars(s, vars): variable expansions; if 'vars' is the output of 'parse_makefile()', you're fine. Returns a variable-expanded version of 's'. """ + import re # This algorithm does multiple expansion, so if vars['foo'] contains # "${bar}", it will expand ${foo} to ${bar}, and then expand @@ -820,7 +819,7 @@ def expand_makefile_vars(s, vars): # according to make's variable expansion semantics. while True: - m = _findvar1_rx.search(s) or _findvar2_rx.search(s) + m = re.search(_findvar1_rx, s) or re.search(_findvar2_rx, s) if m: (beg, end) = m.span() s = s[0:beg] + vars.get(m.group(1)) + s[end:] From 17aa9c44b62c3d20dae1df6a29a24fa97a79342a Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 13 Nov 2020 09:21:14 +0100 Subject: [PATCH 21/24] Move get_python_lib and get_python_inc back to distutils.sysconfig and deprecated them. --- Doc/distutils/apiref.rst | 3 ++ Doc/library/sysconfig.rst | 23 ---------- Lib/distutils/sysconfig.py | 91 ++++++++++++++++++++++++++++++++++++-- Lib/sysconfig.py | 86 ----------------------------------- 4 files changed, 91 insertions(+), 112 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst index 3b1d73f962fc43..743a05ca3553b3 100644 --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -1512,6 +1512,9 @@ for other parts of the :mod:`distutils` package. meaning for other platforms will vary. The file is a platform-specific text file, if it exists. This function is only useful on POSIX platforms. +The following functions are deprecated together with this module and they +have no direct replacement. + .. function:: get_python_inc([plat_specific[, prefix]]) diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst index 4f0a65dd4c9665..d4463f39fda24f 100644 --- a/Doc/library/sysconfig.rst +++ b/Doc/library/sysconfig.rst @@ -224,29 +224,6 @@ Other functions Return the path of :file:`Makefile`. -The following functions have been moved here from :mod:`distutils.sysconfig` -when this module has been deprecated. - -.. function:: get_python_inc([plat_specific[, prefix]]) - - Return the directory for either the general or platform-dependent C include - files. If *plat_specific* is true, the platform-dependent include directory is - returned; if false or omitted, the platform-independent directory is returned. - If *prefix* is given, it is used as either the prefix instead of - :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if - *plat_specific* is true. - - -.. function:: get_python_lib([plat_specific[, standard_lib[, prefix]]]) - - Return the directory for either the general or platform-dependent library - installation. If *plat_specific* is true, the platform-dependent include - directory is returned; if false or omitted, the platform-independent directory - is returned. If *prefix* is given, it is used as either the prefix instead of - :const:`PREFIX`, or as the exec-prefix instead of :const:`EXEC_PREFIX` if - *plat_specific* is true. If *standard_lib* is true, the directory for the - standard library is returned rather than the directory for the installation of - third-party extensions. Using :mod:`sysconfig` as a script ---------------------------------- diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index 4a987b1732416b..d274b8bf5f82d6 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -44,9 +44,7 @@ get_config_var, get_config_vars, get_makefile_filename, - get_python_inc, get_python_version, - get_python_lib, ) # This is better than @@ -78,7 +76,9 @@ def parse_makefile(fn, g=None): _init_nt = partial(_init_non_posix, _config_vars) -# customize_compiler is deprecated and won't be moved to another module +# Following functions are deprecated together with this module and they +# have no direct replacement + def customize_compiler(compiler): """Do any platform-specific customization of a CCompiler instance. @@ -148,3 +148,88 @@ def customize_compiler(compiler): archiver=archiver) compiler.shared_lib_extension = shlib_suffix + + +def get_python_inc(plat_specific=0, prefix=None): + """Return the directory containing installed Python header files. + + If 'plat_specific' is false (the default), this is the path to the + non-platform-specific header files, i.e. Python.h and so on; + otherwise, this is the path to platform-specific header files + (namely pyconfig.h). + + If 'prefix' is supplied, use it instead of sys.base_prefix or + sys.base_exec_prefix -- i.e., ignore 'plat_specific'. + """ + if prefix is None: + prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX + if os.name == "posix": + if python_build: + # Assume the executable is in the build directory. The + # pyconfig.h file should be in the same directory. Since + # the build directory may not be the source directory, we + # must use "srcdir" from the makefile to find the "Include" + # directory. + if plat_specific: + return _sys_home or project_base + else: + incdir = os.path.join(get_config_var('srcdir'), 'Include') + return os.path.normpath(incdir) + python_dir = 'python' + get_python_version() + build_flags + return os.path.join(prefix, "include", python_dir) + elif os.name == "nt": + if python_build: + # Include both the include and PC dir to ensure we can find + # pyconfig.h + return (os.path.join(prefix, "include") + os.path.pathsep + + os.path.join(prefix, "PC")) + return os.path.join(prefix, "include") + else: + raise DistutilsPlatformError( + "I don't know where Python installs its C header files " + "on platform '%s'" % os.name) + + +def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): + """Return the directory containing the Python library (standard or + site additions). + + If 'plat_specific' is true, return the directory containing + platform-specific modules, i.e. any module from a non-pure-Python + module distribution; otherwise, return the platform-shared library + directory. If 'standard_lib' is true, return the directory + containing standard Python library modules; otherwise, return the + directory for site-specific modules. + + If 'prefix' is supplied, use it instead of sys.base_prefix or + sys.base_exec_prefix -- i.e., ignore 'plat_specific'. + """ + if prefix is None: + if standard_lib: + prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX + else: + prefix = plat_specific and EXEC_PREFIX or PREFIX + + if os.name == "posix": + if plat_specific or standard_lib: + # Platform-specific modules (any module from a non-pure-Python + # module distribution) or standard Python library modules. + libdir = sys.platlibdir + else: + # Pure Python + libdir = "lib" + libpython = os.path.join(prefix, libdir, + "python" + get_python_version()) + if standard_lib: + return libpython + else: + return os.path.join(libpython, "site-packages") + elif os.name == "nt": + if standard_lib: + return os.path.join(prefix, "Lib") + else: + return os.path.join(prefix, "Lib", "site-packages") + else: + raise DistutilsPlatformError( + "I don't know where Python installs its library " + "on platform '%s'" % os.name) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 449b225c80ebc2..0e0decd42716ed 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -3,7 +3,6 @@ import os import sys from os.path import pardir, realpath -from distutils.errors import DistutilsPlatformError __all__ = [ 'get_config_h_filename', @@ -717,91 +716,6 @@ def get_python_version(): return _PY_VERSION_SHORT -def get_python_inc(plat_specific=0, prefix=None): - """Return the directory containing installed Python header files. - - If 'plat_specific' is false (the default), this is the path to the - non-platform-specific header files, i.e. Python.h and so on; - otherwise, this is the path to platform-specific header files - (namely pyconfig.h). - - If 'prefix' is supplied, use it instead of sys.base_prefix or - sys.base_exec_prefix -- i.e., ignore 'plat_specific'. - """ - if prefix is None: - prefix = plat_specific and _BASE_EXEC_PREFIX or _BASE_PREFIX - if os.name == "posix": - if _PYTHON_BUILD: - # Assume the executable is in the build directory. The - # pyconfig.h file should be in the same directory. Since - # the build directory may not be the source directory, we - # must use "srcdir" from the makefile to find the "Include" - # directory. - if plat_specific: - return _sys_home or _PROJECT_BASE - else: - incdir = os.path.join(get_config_var('srcdir'), 'Include') - return os.path.normpath(incdir) - python_dir = 'python' + get_python_version() + build_flags - return os.path.join(prefix, "include", python_dir) - elif os.name == "nt": - if _PYTHON_BUILD: - # Include both the include and PC dir to ensure we can find - # pyconfig.h - return (os.path.join(prefix, "include") + os.path.pathsep + - os.path.join(prefix, "PC")) - return os.path.join(prefix, "include") - else: - raise DistutilsPlatformError( - "I don't know where Python installs its C header files " - "on platform '%s'" % os.name) - - -def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): - """Return the directory containing the Python library (standard or - site additions). - - If 'plat_specific' is true, return the directory containing - platform-specific modules, i.e. any module from a non-pure-Python - module distribution; otherwise, return the platform-shared library - directory. If 'standard_lib' is true, return the directory - containing standard Python library modules; otherwise, return the - directory for site-specific modules. - - If 'prefix' is supplied, use it instead of sys.base_prefix or - sys.base_exec_prefix -- i.e., ignore 'plat_specific'. - """ - if prefix is None: - if standard_lib: - prefix = plat_specific and _BASE_EXEC_PREFIX or _BASE_PREFIX - else: - prefix = plat_specific and _EXEC_PREFIX or _PREFIX - - if os.name == "posix": - if plat_specific or standard_lib: - # Platform-specific modules (any module from a non-pure-Python - # module distribution) or standard Python library modules. - libdir = sys.platlibdir - else: - # Pure Python - libdir = "lib" - libpython = os.path.join(prefix, libdir, - "python" + get_python_version()) - if standard_lib: - return libpython - else: - return os.path.join(libpython, "site-packages") - elif os.name == "nt": - if standard_lib: - return os.path.join(prefix, "Lib") - else: - return os.path.join(prefix, "Lib", "site-packages") - else: - raise DistutilsPlatformError( - "I don't know where Python installs its library " - "on platform '%s'" % os.name) - - def expand_makefile_vars(s, vars): """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in 'string' according to 'vars' (a dictionary mapping variable names to From be181b67cef5393a85535245918a9267c8b0250b Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Mon, 15 Feb 2021 12:53:59 +0100 Subject: [PATCH 22/24] News entry --- .../NEWS.d/next/Library/2021-02-15-12-52-23.bpo-41282.SenEje.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2021-02-15-12-52-23.bpo-41282.SenEje.rst diff --git a/Misc/NEWS.d/next/Library/2021-02-15-12-52-23.bpo-41282.SenEje.rst b/Misc/NEWS.d/next/Library/2021-02-15-12-52-23.bpo-41282.SenEje.rst new file mode 100644 index 00000000000000..95ac1831dbf2d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-02-15-12-52-23.bpo-41282.SenEje.rst @@ -0,0 +1 @@ +:mod:`distutils.sysconfig` has been merged to :mod:`sysconfig`. From e253a3d33a49f469468374492b7bb89c3300b4d0 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Fri, 16 Apr 2021 16:01:24 +0200 Subject: [PATCH 23/24] Restore build_flags accidentally removed during a rebase --- Lib/distutils/sysconfig.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index d274b8bf5f82d6..439040deb5619d 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -79,6 +79,19 @@ def parse_makefile(fn, g=None): # Following functions are deprecated together with this module and they # have no direct replacement +# Calculate the build qualifier flags if they are defined. Adding the flags +# to the include and lib directories only makes sense for an installation, not +# an in-source build. +build_flags = '' +try: + if not python_build: + build_flags = sys.abiflags +except AttributeError: + # It's not a configure-based build, so the sys module doesn't have + # this attribute, which is fine. + pass + + def customize_compiler(compiler): """Do any platform-specific customization of a CCompiler instance. From cd8e387f4530c1544a712a9ed9d464532a3975df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lum=C3=ADr=20=27Frenzy=27=20Balhar?= Date: Sun, 18 Apr 2021 11:26:06 +0200 Subject: [PATCH 24/24] Update Doc/distutils/apiref.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric Araujo --- Doc/distutils/apiref.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst index 743a05ca3553b3..e4437f4106b519 100644 --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -1453,7 +1453,7 @@ name. .. module:: distutils.sysconfig :synopsis: Low-level access to configuration information of the Python interpreter. .. deprecated:: 3.10 - :mod:`distutils.sysconfig` has been merged to :mod:`sysconfig`. + :mod:`distutils.sysconfig` has been merged into :mod:`sysconfig`. .. moduleauthor:: Fred L. Drake, Jr. .. moduleauthor:: Greg Ward .. sectionauthor:: Fred L. Drake, Jr.