This commit is contained in:
lz_db
2026-10-16 22:48:30 +08:00
parent 190de72571
commit 0b36fd3383
3161 changed files with 12787 additions and 77274 deletions
@@ -9,30 +9,15 @@ Written by: Fred L. Drake, Jr.
Email: <fdrake@acm.org>
"""
from __future__ import annotations
import functools
import os
import pathlib
import re
import sys
import sysconfig
from typing import TYPE_CHECKING, Literal, overload
import pathlib
from jaraco.functools import pass_none
from .ccompiler import CCompiler
from .compat import py39
from .errors import DistutilsPlatformError
from .util import is_mingw
if TYPE_CHECKING:
from typing_extensions import deprecated
else:
def deprecated(message):
return lambda fn: fn
from . import py39compat
from ._functools import pass_none
IS_PYPY = '__pypy__' in sys.builtin_module_names
@@ -119,10 +104,10 @@ def get_python_version():
leaving off the patchlevel. Sample return values could be '1.5'
or '2.2'.
"""
return f'{sys.version_info.major}.{sys.version_info.minor}'
return '%d.%d' % sys.version_info[:2]
def get_python_inc(plat_specific: bool = False, prefix: str | None = None) -> str:
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
@@ -135,30 +120,22 @@ def get_python_inc(plat_specific: bool = False, prefix: str | None = None) -> st
"""
default_prefix = BASE_EXEC_PREFIX if plat_specific else BASE_PREFIX
resolved_prefix = prefix if prefix is not None else default_prefix
# MinGW imitates posix like layout, but os.name != posix
os_name = "posix" if is_mingw() else os.name
try:
getter = globals()[f'_get_python_inc_{os_name}']
getter = globals()[f'_get_python_inc_{os.name}']
except KeyError:
raise DistutilsPlatformError(
"I don't know where Python installs its C header files "
f"on platform '{os.name}'"
"on platform '%s'" % os.name
)
return getter(resolved_prefix, prefix, plat_specific)
@pass_none
def _extant(path):
"""
Replace path with None if it doesn't exist.
"""
return path if os.path.exists(path) else None
def _get_python_inc_posix(prefix, spec_prefix, plat_specific):
if IS_PYPY and sys.version_info < (3, 8):
return os.path.join(prefix, 'include')
return (
_get_python_inc_posix_python(plat_specific)
or _extant(_get_python_inc_from_config(plat_specific, spec_prefix))
or _get_python_inc_from_config(plat_specific, spec_prefix)
or _get_python_inc_posix_prefix(prefix)
)
@@ -210,11 +187,12 @@ def _get_python_inc_posix_prefix(prefix):
def _get_python_inc_nt(prefix, spec_prefix, plat_specific):
if python_build:
# Include both include dirs to ensure we can find pyconfig.h
# 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.dirname(sysconfig.get_config_h_filename())
+ os.path.join(prefix, "PC")
)
return os.path.join(prefix, "include")
@@ -227,9 +205,7 @@ def _posix_lib(standard_lib, libpython, early_prefix, prefix):
return os.path.join(libpython, "site-packages")
def get_python_lib(
plat_specific: bool = False, standard_lib: bool = False, prefix: str | None = None
) -> str:
def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
"""Return the directory containing the Python library (standard or
site additions).
@@ -244,6 +220,14 @@ def get_python_lib(
sys.base_exec_prefix -- i.e., ignore 'plat_specific'.
"""
if IS_PYPY and sys.version_info < (3, 8):
# PyPy-specific schema
if prefix is None:
prefix = PREFIX
if standard_lib:
return os.path.join(prefix, "lib-python", sys.version[0])
return os.path.join(prefix, 'site-packages')
early_prefix = prefix
if prefix is None:
@@ -252,7 +236,7 @@ def get_python_lib(
else:
prefix = plat_specific and EXEC_PREFIX or PREFIX
if os.name == "posix" or is_mingw():
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.
@@ -270,38 +254,34 @@ def get_python_lib(
return os.path.join(prefix, "Lib", "site-packages")
else:
raise DistutilsPlatformError(
f"I don't know where Python installs its library on platform '{os.name}'"
"I don't know where Python installs its library "
"on platform '%s'" % os.name
)
@functools.lru_cache
def _customize_macos():
"""
Perform first-time customization of compiler-related
config vars on macOS. Use after a compiler is known
to be needed. This customization exists 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.
"""
sys.platform == "darwin" and __import__('_osx_support').customize_compiler(
get_config_vars()
)
def customize_compiler(compiler: CCompiler) -> None:
def customize_compiler(compiler): # noqa: C901
"""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 in ["unix", "cygwin"] or (
compiler.compiler_type == "mingw32" and is_mingw()
):
_customize_macos()
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,
@@ -309,7 +289,6 @@ def customize_compiler(compiler: CCompiler) -> None:
cflags,
ccshared,
ldshared,
ldcxxshared,
shlib_suffix,
ar,
ar_flags,
@@ -319,14 +298,11 @@ def customize_compiler(compiler: CCompiler) -> None:
'CFLAGS',
'CCSHARED',
'LDSHARED',
'LDCXXSHARED',
'SHLIB_SUFFIX',
'AR',
'ARFLAGS',
)
cxxflags = cflags
if 'CC' in os.environ:
newcc = os.environ['CC']
if 'LDSHARED' not in os.environ and ldshared.startswith(cc):
@@ -334,42 +310,38 @@ def customize_compiler(compiler: CCompiler) -> None:
# command for LDSHARED as well
ldshared = newcc + ldshared[len(cc) :]
cc = newcc
cxx = os.environ.get('CXX', cxx)
ldshared = os.environ.get('LDSHARED', ldshared)
ldcxxshared = os.environ.get('LDCXXSHARED', ldcxxshared)
cpp = os.environ.get(
'CPP',
cc + " -E", # not always
)
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
ldshared = _add_flags(ldshared, 'LD')
ldcxxshared = _add_flags(ldcxxshared, 'LD')
cflags = os.environ.get('CFLAGS', cflags)
ldshared = _add_flags(ldshared, 'C')
cxxflags = os.environ.get('CXXFLAGS', cxxflags)
ldcxxshared = _add_flags(ldcxxshared, 'CXX')
cpp = _add_flags(cpp, 'CPP')
cflags = _add_flags(cflags, 'CPP')
cxxflags = _add_flags(cxxflags, 'CPP')
ldshared = _add_flags(ldshared, 'CPP')
ldcxxshared = _add_flags(ldcxxshared, 'CPP')
ar = os.environ.get('AR', ar)
archiver = ar + ' ' + os.environ.get('ARFLAGS', ar_flags)
cc_cmd = cc + ' ' + cflags
cxx_cmd = cxx + ' ' + cxxflags
compiler.set_executables(
preprocessor=cpp,
compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared,
compiler_cxx=cxx_cmd,
compiler_so_cxx=cxx_cmd + ' ' + ccshared,
compiler_cxx=cxx,
linker_so=ldshared,
linker_so_cxx=ldcxxshared,
linker_exe=cc,
linker_exe_cxx=cxx,
archiver=archiver,
)
@@ -379,12 +351,19 @@ def customize_compiler(compiler: CCompiler) -> None:
compiler.shared_lib_extension = shlib_suffix
def get_config_h_filename() -> str:
def get_config_h_filename():
"""Return full pathname of installed pyconfig.h file."""
return sysconfig.get_config_h_filename()
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
return os.path.join(inc_dir, 'pyconfig.h')
else:
return sysconfig.get_config_h_filename()
def get_makefile_filename() -> str:
def get_makefile_filename():
"""Return full pathname of installed Makefile from the Python build."""
return sysconfig.get_makefile_filename()
@@ -416,11 +395,7 @@ def parse_makefile(fn, g=None): # noqa: C901
from distutils.text_file import TextFile
fp = TextFile(
fn,
strip_comments=True,
skip_blanks=True,
join_lines=True,
errors="surrogateescape",
fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape"
)
if g is None:
@@ -499,6 +474,7 @@ def parse_makefile(fn, g=None): # noqa: C901
del notdone[name]
if name.startswith('PY_') and name[3:] in renamed_variables:
name = name[3:]
if name not in done:
done[name] = value
@@ -546,11 +522,7 @@ def expand_makefile_vars(s, vars):
_config_vars = None
@overload
def get_config_vars() -> dict[str, str | int]: ...
@overload
def get_config_vars(arg: str, /, *args: str) -> list[str | int]: ...
def get_config_vars(*args: str) -> list[str | int] | dict[str, str | int]:
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
@@ -563,19 +535,18 @@ def get_config_vars(*args: str) -> list[str | int] | dict[str, str | int]:
global _config_vars
if _config_vars is None:
_config_vars = sysconfig.get_config_vars().copy()
py39.add_ext_suffix(_config_vars)
py39compat.add_ext_suffix(_config_vars)
return [_config_vars.get(name) for name in args] if args else _config_vars
if args:
vals = []
for name in args:
vals.append(_config_vars.get(name))
return vals
else:
return _config_vars
@overload
@deprecated(
"SO is deprecated, use EXT_SUFFIX. Support will be removed when this module is synchronized with stdlib Python 3.11"
)
def get_config_var(name: Literal["SO"]) -> int | str | None: ...
@overload
def get_config_var(name: str) -> int | str | None: ...
def get_config_var(name: str) -> int | str | None:
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)
@@ -585,14 +556,3 @@ def get_config_var(name: str) -> int | str | None:
warnings.warn('SO is deprecated, use EXT_SUFFIX', DeprecationWarning, 2)
return get_config_vars().get(name)
@pass_none
def _add_flags(value: str, type: str) -> str:
"""
Add any flags from the environment for the given type.
type is the prefix to FLAGS in the environment key (e.g. "C" for "CFLAGS").
"""
flags = os.environ.get(f'{type}FLAGS')
return f'{value} {flags}' if flags else value