mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00
bpo-41282: (PEP 632) Deprecate distutils.sysconfig (partial implementation of the PEP) (GH-23142)
This change: * merges `distutils.sysconfig` into `sysconfig` while keeping the original functionality and * marks `distutils.sysconfig` as deprecated https://bugs.python.org/issue41282
This commit is contained in:
parent
b9ad88be03
commit
90d02e5e63
15 changed files with 209 additions and 443 deletions
|
@ -1452,6 +1452,8 @@ name.
|
||||||
|
|
||||||
.. module:: distutils.sysconfig
|
.. module:: distutils.sysconfig
|
||||||
:synopsis: Low-level access to configuration information of the Python interpreter.
|
:synopsis: Low-level access to configuration information of the Python interpreter.
|
||||||
|
.. deprecated:: 3.10
|
||||||
|
:mod:`distutils.sysconfig` has been merged into :mod:`sysconfig`.
|
||||||
.. moduleauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
|
.. moduleauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
|
||||||
.. moduleauthor:: Greg Ward <gward@python.net>
|
.. moduleauthor:: Greg Ward <gward@python.net>
|
||||||
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
|
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
|
||||||
|
@ -1510,6 +1512,9 @@ for other parts of the :mod:`distutils` package.
|
||||||
meaning for other platforms will vary. The file is a platform-specific text
|
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.
|
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]])
|
.. function:: get_python_inc([plat_specific[, prefix]])
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,7 @@ Other functions
|
||||||
|
|
||||||
Return the path of :file:`Makefile`.
|
Return the path of :file:`Makefile`.
|
||||||
|
|
||||||
|
|
||||||
Using :mod:`sysconfig` as a script
|
Using :mod:`sysconfig` as a script
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ Provides the Extension class, used to describe C/C++ extension
|
||||||
modules in setup scripts."""
|
modules in setup scripts."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
# This class is really only used by the "build_ext" command, so it might
|
# 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()
|
line = file.readline()
|
||||||
if line is None: # eof
|
if line is None: # eof
|
||||||
break
|
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
|
continue
|
||||||
|
|
||||||
if line[0] == line[-1] == "*":
|
if line[0] == line[-1] == "*":
|
||||||
|
|
|
@ -13,56 +13,71 @@ import _imp
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from .errors import DistutilsPlatformError
|
from .errors import DistutilsPlatformError
|
||||||
|
|
||||||
# These are needed in a couple of spots, so just compute them once.
|
from sysconfig import (
|
||||||
PREFIX = os.path.normpath(sys.prefix)
|
_PREFIX as PREFIX,
|
||||||
EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
|
_BASE_PREFIX as BASE_PREFIX,
|
||||||
BASE_PREFIX = os.path.normpath(sys.base_prefix)
|
_EXEC_PREFIX as EXEC_PREFIX,
|
||||||
BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
|
_BASE_EXEC_PREFIX as BASE_EXEC_PREFIX,
|
||||||
|
_PROJECT_BASE as project_base,
|
||||||
|
_PYTHON_BUILD as python_build,
|
||||||
|
_init_posix as sysconfig_init_posix,
|
||||||
|
parse_config_h as sysconfig_parse_config_h,
|
||||||
|
_parse_makefile as sysconfig_parse_makefile,
|
||||||
|
|
||||||
# Path to the base directory of the project. On Windows the binary may
|
_init_non_posix,
|
||||||
# live in project/PCbuild/win32 or project/PCbuild/amd64.
|
_is_python_source_dir,
|
||||||
# set for cross builds
|
_sys_home,
|
||||||
if "_PYTHON_PROJECT_BASE" in os.environ:
|
|
||||||
project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"])
|
_variable_rx,
|
||||||
else:
|
_findvar1_rx,
|
||||||
if sys.executable:
|
_findvar2_rx,
|
||||||
project_base = os.path.dirname(os.path.abspath(sys.executable))
|
|
||||||
else:
|
expand_makefile_vars,
|
||||||
# sys.executable can be empty if argv[0] has been changed and Python is
|
is_python_build,
|
||||||
# unable to retrieve the real program name
|
get_config_h_filename,
|
||||||
project_base = os.getcwd()
|
get_config_var,
|
||||||
|
get_config_vars,
|
||||||
|
get_makefile_filename,
|
||||||
|
get_python_version,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
'the distutils.sysconfig module is deprecated, use sysconfig instead',
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# python_build: (Boolean) if true, we're either building Python or
|
# Following functions are the same as in sysconfig but with different API
|
||||||
# building an extension with an un-installed Python, so we use
|
def parse_config_h(fp, g=None):
|
||||||
# different (hard-wired) directories.
|
return sysconfig_parse_config_h(fp, vars=g)
|
||||||
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 parse_makefile(fn, g=None):
|
||||||
def _fix_pcbuild(d):
|
return sysconfig_parse_makefile(fn, vars=g, keep_unresolved=False)
|
||||||
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():
|
_python_build = partial(is_python_build, check_home=True)
|
||||||
if _sys_home:
|
_init_posix = partial(sysconfig_init_posix, _config_vars)
|
||||||
return _is_python_source_dir(_sys_home)
|
_init_nt = partial(_init_non_posix, _config_vars)
|
||||||
return _is_python_source_dir(project_base)
|
|
||||||
|
|
||||||
python_build = _python_build()
|
|
||||||
|
|
||||||
|
# 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
|
# 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
|
# to the include and lib directories only makes sense for an installation, not
|
||||||
|
@ -76,12 +91,76 @@ except AttributeError:
|
||||||
# this attribute, which is fine.
|
# this attribute, which is fine.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_python_version():
|
|
||||||
"""Return a string containing the major and minor Python version,
|
def customize_compiler(compiler):
|
||||||
leaving off the patchlevel. Sample return values could be '1.5'
|
"""Do any platform-specific customization of a CCompiler instance.
|
||||||
or '2.2'.
|
|
||||||
|
Mainly needed on Unix, so we can plug in the information that
|
||||||
|
varies across Unices and is stored in Python's Makefile.
|
||||||
"""
|
"""
|
||||||
return '%d.%d' % sys.version_info[:2]
|
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.
|
||||||
|
if not _config_vars.get('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_python_inc(plat_specific=0, prefix=None):
|
def get_python_inc(plat_specific=0, prefix=None):
|
||||||
|
@ -167,389 +246,3 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
|
||||||
raise DistutilsPlatformError(
|
raise DistutilsPlatformError(
|
||||||
"I don't know where Python installs its library "
|
"I don't know where Python installs its library "
|
||||||
"on platform '%s'" % os.name)
|
"on platform '%s'" % os.name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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 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():
|
|
||||||
"""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
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
from test.support import run_unittest, missing_compiler_executable
|
from test.support import run_unittest, missing_compiler_executable
|
||||||
|
|
||||||
|
@ -13,6 +14,15 @@ class BuildCLibTestCase(support.TempdirManager,
|
||||||
support.LoggingSilencer,
|
support.LoggingSilencer,
|
||||||
unittest.TestCase):
|
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):
|
def test_check_library_dist(self):
|
||||||
pkg_dir, dist = self.create_dist()
|
pkg_dir, dist = self.create_dist()
|
||||||
cmd = build_clib(dist)
|
cmd = build_clib(dist)
|
||||||
|
|
|
@ -35,6 +35,7 @@ class BuildExtTestCase(TempdirManager,
|
||||||
site.USER_BASE = self.mkdtemp()
|
site.USER_BASE = self.mkdtemp()
|
||||||
from distutils.command import build_ext
|
from distutils.command import build_ext
|
||||||
build_ext.USER_BASE = site.USER_BASE
|
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
|
# bpo-30132: On Windows, a .pdb file may be created in the current
|
||||||
# working directory. Create a temporary working directory to cleanup
|
# working directory. Create a temporary working directory to cleanup
|
||||||
|
@ -48,6 +49,8 @@ class BuildExtTestCase(TempdirManager,
|
||||||
site.USER_BASE = self.old_user_base
|
site.USER_BASE = self.old_user_base
|
||||||
from distutils.command import build_ext
|
from distutils.command import build_ext
|
||||||
build_ext.USER_BASE = self.old_user_base
|
build_ext.USER_BASE = self.old_user_base
|
||||||
|
sysconfig._config_vars.clear()
|
||||||
|
sysconfig._config_vars.update(self.old_config_vars)
|
||||||
super(BuildExtTestCase, self).tearDown()
|
super(BuildExtTestCase, self).tearDown()
|
||||||
|
|
||||||
def build_ext(self, *args, **kwargs):
|
def build_ext(self, *args, **kwargs):
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import sysconfig
|
||||||
from test.support import run_unittest, missing_compiler_executable
|
from test.support import run_unittest, missing_compiler_executable
|
||||||
|
|
||||||
from distutils.command.config import dump_file, config
|
from distutils.command.config import dump_file, config
|
||||||
|
@ -21,9 +22,12 @@ class ConfigTestCase(support.LoggingSilencer,
|
||||||
self._logs = []
|
self._logs = []
|
||||||
self.old_log = log.info
|
self.old_log = log.info
|
||||||
log.info = self._info
|
log.info = self._info
|
||||||
|
self.old_config_vars = dict(sysconfig._CONFIG_VARS)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
log.info = self.old_log
|
log.info = self.old_log
|
||||||
|
sysconfig._CONFIG_VARS.clear()
|
||||||
|
sysconfig._CONFIG_VARS.update(self.old_config_vars)
|
||||||
super(ConfigTestCase, self).tearDown()
|
super(ConfigTestCase, self).tearDown()
|
||||||
|
|
||||||
def test_dump_file(self):
|
def test_dump_file(self):
|
||||||
|
|
|
@ -29,6 +29,15 @@ class InstallTestCase(support.TempdirManager,
|
||||||
support.LoggingSilencer,
|
support.LoggingSilencer,
|
||||||
unittest.TestCase):
|
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):
|
def test_home_installation_scheme(self):
|
||||||
# This ensure two things:
|
# This ensure two things:
|
||||||
# - that --home generates the desired set of directory names
|
# - that --home generates the desired set of directory names
|
||||||
|
|
|
@ -12,6 +12,7 @@ class UnixCCompilerTestCase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self._backup_platform = sys.platform
|
self._backup_platform = sys.platform
|
||||||
self._backup_get_config_var = sysconfig.get_config_var
|
self._backup_get_config_var = sysconfig.get_config_var
|
||||||
|
self._backup_config_vars = dict(sysconfig._config_vars)
|
||||||
class CompilerWrapper(UnixCCompiler):
|
class CompilerWrapper(UnixCCompiler):
|
||||||
def rpath_foo(self):
|
def rpath_foo(self):
|
||||||
return self.runtime_library_dir_option('/foo')
|
return self.runtime_library_dir_option('/foo')
|
||||||
|
@ -20,6 +21,8 @@ class UnixCCompilerTestCase(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
sys.platform = self._backup_platform
|
sys.platform = self._backup_platform
|
||||||
sysconfig.get_config_var = self._backup_get_config_var
|
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")
|
@unittest.skipIf(sys.platform == 'win32', "can't test on Windows")
|
||||||
def test_runtime_libdir_option(self):
|
def test_runtime_libdir_option(self):
|
||||||
|
|
|
@ -54,7 +54,8 @@ class UtilTestCase(support.EnvironGuard, unittest.TestCase):
|
||||||
os.uname = self.uname
|
os.uname = self.uname
|
||||||
else:
|
else:
|
||||||
del os.uname
|
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()
|
super(UtilTestCase, self).tearDown()
|
||||||
|
|
||||||
def _set_uname(self, uname):
|
def _set_uname(self, uname):
|
||||||
|
|
|
@ -90,7 +90,8 @@ sys.path = {additional_paths or []} + sys.path
|
||||||
sys.argv[1:] = {args}
|
sys.argv[1:] = {args}
|
||||||
runpy.run_module("pip", run_name="__main__", alter_sys=True)
|
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():
|
def version():
|
||||||
|
|
|
@ -130,6 +130,12 @@ _BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
|
||||||
_CONFIG_VARS = None
|
_CONFIG_VARS = None
|
||||||
_USER_BASE = None
|
_USER_BASE = None
|
||||||
|
|
||||||
|
# Regexes needed for parsing Makefile (and similar syntaxes,
|
||||||
|
# like old-style Setup files).
|
||||||
|
_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):
|
def _safe_realpath(path):
|
||||||
try:
|
try:
|
||||||
|
@ -215,19 +221,14 @@ def _get_default_scheme():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_makefile(filename, vars=None):
|
def _parse_makefile(filename, vars=None, keep_unresolved=True):
|
||||||
"""Parse a Makefile-style file.
|
"""Parse a Makefile-style file.
|
||||||
|
|
||||||
A dictionary containing name/value pairs is returned. If an
|
A dictionary containing name/value pairs is returned. If an
|
||||||
optional dictionary is passed in as the second argument, it is
|
optional dictionary is passed in as the second argument, it is
|
||||||
used instead of a new dictionary.
|
used instead of a new dictionary.
|
||||||
"""
|
"""
|
||||||
# Regexes needed for parsing Makefile (and similar syntaxes,
|
|
||||||
# like old-style Setup files).
|
|
||||||
import re
|
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:
|
if vars is None:
|
||||||
vars = {}
|
vars = {}
|
||||||
|
@ -241,7 +242,7 @@ def _parse_makefile(filename, vars=None):
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.startswith('#') or line.strip() == '':
|
if line.startswith('#') or line.strip() == '':
|
||||||
continue
|
continue
|
||||||
m = _variable_rx.match(line)
|
m = re.match(_variable_rx, line)
|
||||||
if m:
|
if m:
|
||||||
n, v = m.group(1, 2)
|
n, v = m.group(1, 2)
|
||||||
v = v.strip()
|
v = v.strip()
|
||||||
|
@ -274,8 +275,8 @@ def _parse_makefile(filename, vars=None):
|
||||||
while len(variables) > 0:
|
while len(variables) > 0:
|
||||||
for name in tuple(variables):
|
for name in tuple(variables):
|
||||||
value = notdone[name]
|
value = notdone[name]
|
||||||
m1 = _findvar1_rx.search(value)
|
m1 = re.search(_findvar1_rx, value)
|
||||||
m2 = _findvar2_rx.search(value)
|
m2 = re.search(_findvar2_rx, value)
|
||||||
if m1 and m2:
|
if m1 and m2:
|
||||||
m = m1 if m1.start() < m2.start() else m2
|
m = m1 if m1.start() < m2.start() else m2
|
||||||
else:
|
else:
|
||||||
|
@ -330,9 +331,12 @@ def _parse_makefile(filename, vars=None):
|
||||||
done[name] = value
|
done[name] = value
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# 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");
|
# bogus variable reference (e.g. "prefix=$/opt/python");
|
||||||
# just drop it since we can't deal
|
# just drop it since we can't deal
|
||||||
done[name] = value
|
|
||||||
variables.remove(name)
|
variables.remove(name)
|
||||||
|
|
||||||
# strip spurious spaces
|
# strip spurious spaces
|
||||||
|
@ -712,6 +716,32 @@ def get_python_version():
|
||||||
return _PY_VERSION_SHORT
|
return _PY_VERSION_SHORT
|
||||||
|
|
||||||
|
|
||||||
|
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'.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
# 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 = 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:]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
def _print_dict(title, data):
|
def _print_dict(title, data):
|
||||||
for index, (key, value) in enumerate(sorted(data.items())):
|
for index, (key, value) in enumerate(sorted(data.items())):
|
||||||
if index == 0:
|
if index == 0:
|
||||||
|
|
|
@ -1667,6 +1667,7 @@ def missing_compiler_executable(cmd_names=[]):
|
||||||
missing.
|
missing.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# TODO (PEP 632): alternate check without using distutils
|
||||||
from distutils import ccompiler, sysconfig, spawn, errors
|
from distutils import ccompiler, sysconfig, spawn, errors
|
||||||
compiler = ccompiler.new_compiler()
|
compiler = ccompiler.new_compiler()
|
||||||
sysconfig.customize_compiler(compiler)
|
sysconfig.customize_compiler(compiler)
|
||||||
|
|
|
@ -70,6 +70,7 @@ unittest.main()
|
||||||
|
|
||||||
class TestCParser(TempdirManager, unittest.TestCase):
|
class TestCParser(TempdirManager, unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
self._backup_config_vars = dict(sysconfig._CONFIG_VARS)
|
||||||
cmd = support.missing_compiler_executable()
|
cmd = support.missing_compiler_executable()
|
||||||
if cmd is not None:
|
if cmd is not None:
|
||||||
self.skipTest("The %r command is not found" % cmd)
|
self.skipTest("The %r command is not found" % cmd)
|
||||||
|
@ -81,6 +82,8 @@ class TestCParser(TempdirManager, unittest.TestCase):
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super(TestCParser, self).tearDown()
|
super(TestCParser, self).tearDown()
|
||||||
|
sysconfig._CONFIG_VARS.clear()
|
||||||
|
sysconfig._CONFIG_VARS.update(self._backup_config_vars)
|
||||||
|
|
||||||
def build_extension(self, grammar_source):
|
def build_extension(self, grammar_source):
|
||||||
grammar = parse_string(grammar_source, GrammarParser)
|
grammar = parse_string(grammar_source, GrammarParser)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
:mod:`distutils.sysconfig` has been merged to :mod:`sysconfig`.
|
Loading…
Add table
Add a link
Reference in a new issue