Skip to content

Commit f23c3dc

Browse files
FFY00srinivasreddy
authored andcommitted
pythonGH-127178: improve compatibility in _sysconfig_vars_(...).json (python#128558)
1 parent dc90f41 commit f23c3dc

File tree

3 files changed

+61
-23
lines changed

3 files changed

+61
-23
lines changed

Lib/sysconfig/__init__.py

+41-20
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,10 @@ def _getuserbase():
116116
if env_base:
117117
return env_base
118118

119-
# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
120-
if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
119+
# Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories.
120+
# Use _PYTHON_HOST_PLATFORM to get the correct platform when cross-compiling.
121+
system_name = os.environ.get('_PYTHON_HOST_PLATFORM', sys.platform).split('-')[0]
122+
if system_name in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
121123
return None
122124

123125
def joinuser(*args):
@@ -342,34 +344,53 @@ def get_makefile_filename():
342344
return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile')
343345

344346

347+
def _import_from_directory(path, name):
348+
if name not in sys.modules:
349+
import importlib.machinery
350+
import importlib.util
351+
352+
spec = importlib.machinery.PathFinder.find_spec(name, [path])
353+
module = importlib.util.module_from_spec(spec)
354+
spec.loader.exec_module(module)
355+
sys.modules[name] = module
356+
return sys.modules[name]
357+
358+
345359
def _get_sysconfigdata_name():
346360
multiarch = getattr(sys.implementation, '_multiarch', '')
347361
return os.environ.get(
348362
'_PYTHON_SYSCONFIGDATA_NAME',
349363
f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}',
350364
)
351365

352-
def _init_posix(vars):
353-
"""Initialize the module as appropriate for POSIX systems."""
354-
# _sysconfigdata is generated at build time, see _generate_posix_vars()
366+
367+
def _get_sysconfigdata():
368+
import importlib
369+
355370
name = _get_sysconfigdata_name()
371+
path = os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')
372+
module = _import_from_directory(path, name) if path else importlib.import_module(name)
356373

357-
# For cross builds, the path to the target's sysconfigdata must be specified
358-
# so it can be imported. It cannot be in PYTHONPATH, as foreign modules in
359-
# sys.path can cause crashes when loaded by the host interpreter.
360-
# Rely on truthiness as a valueless env variable is still an empty string.
361-
# See OS X note in _generate_posix_vars re _sysconfigdata.
362-
if (path := os.environ.get('_PYTHON_SYSCONFIGDATA_PATH')):
363-
from importlib.machinery import FileFinder, SourceFileLoader, SOURCE_SUFFIXES
364-
from importlib.util import module_from_spec
365-
spec = FileFinder(path, (SourceFileLoader, SOURCE_SUFFIXES)).find_spec(name)
366-
_temp = module_from_spec(spec)
367-
spec.loader.exec_module(_temp)
368-
else:
369-
_temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
370-
build_time_vars = _temp.build_time_vars
374+
return module.build_time_vars
375+
376+
377+
def _installation_is_relocated():
378+
"""Is the Python installation running from a different prefix than what was targetted when building?"""
379+
if os.name != 'posix':
380+
raise NotImplementedError('sysconfig._installation_is_relocated() is currently only supported on POSIX')
381+
382+
data = _get_sysconfigdata()
383+
return (
384+
data['prefix'] != getattr(sys, 'base_prefix', '')
385+
or data['exec_prefix'] != getattr(sys, 'base_exec_prefix', '')
386+
)
387+
388+
389+
def _init_posix(vars):
390+
"""Initialize the module as appropriate for POSIX systems."""
371391
# GH-126920: Make sure we don't overwrite any of the keys already set
372-
vars.update(build_time_vars | vars)
392+
vars.update(_get_sysconfigdata() | vars)
393+
373394

374395
def _init_non_posix(vars):
375396
"""Initialize the module as appropriate for NT"""

Lib/sysconfig/__main__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,14 @@ def _generate_posix_vars():
232232

233233
print(f'Written {destfile}')
234234

235+
install_vars = get_config_vars()
236+
# Fix config vars to match the values after install (of the default environment)
237+
install_vars['projectbase'] = install_vars['BINDIR']
238+
install_vars['srcdir'] = install_vars['LIBPL']
235239
# Write a JSON file with the output of sysconfig.get_config_vars
236240
jsonfile = os.path.join(pybuilddir, _get_json_data_name())
237241
with open(jsonfile, 'w') as f:
238-
json.dump(get_config_vars(), f, indent=2)
242+
json.dump(install_vars, f, indent=2)
239243

240244
print(f'Written {jsonfile}')
241245

Lib/test/test_sysconfig.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -650,8 +650,21 @@ def test_sysconfigdata_json(self):
650650

651651
system_config_vars = get_config_vars()
652652

653-
# Ignore keys in the check
654-
for key in ('projectbase', 'srcdir'):
653+
ignore_keys = set()
654+
# Keys dependent on Python being run outside the build directrory
655+
if sysconfig.is_python_build():
656+
ignore_keys |= {'srcdir'}
657+
# Keys dependent on the executable location
658+
if os.path.dirname(sys.executable) != system_config_vars['BINDIR']:
659+
ignore_keys |= {'projectbase'}
660+
# Keys dependent on the environment (different inside virtual environments)
661+
if sys.prefix != sys.base_prefix:
662+
ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase'}
663+
# Keys dependent on Python being run from the prefix targetted when building (different on relocatable installs)
664+
if sysconfig._installation_is_relocated():
665+
ignore_keys |= {'prefix', 'exec_prefix', 'base', 'platbase', 'installed_base', 'installed_platbase'}
666+
667+
for key in ignore_keys:
655668
json_config_vars.pop(key)
656669
system_config_vars.pop(key)
657670

0 commit comments

Comments
 (0)