+import json
import os
import sys
+import types
from sysconfig import (
_ALWAYS_STR,
_PYTHON_BUILD,
print ("}", file=stream)
+def _get_pybuilddir():
+ pybuilddir = f'build/lib.{get_platform()}-{get_python_version()}'
+ if hasattr(sys, "gettotalrefcount"):
+ pybuilddir += '-pydebug'
+ return pybuilddir
+
+
+def _get_json_data_name():
+ name = _get_sysconfigdata_name()
+ assert name.startswith('_sysconfigdata')
+ return name.replace('_sysconfigdata', '_sysconfig_vars') + '.json'
+
+
def _generate_posix_vars():
"""Generate the Python module containing build-time variables."""
vars = {}
if _PYTHON_BUILD:
vars['BLDSHARED'] = vars['LDSHARED']
+ name = _get_sysconfigdata_name()
+
# There's a chicken-and-egg situation on OS X with regards to the
# _sysconfigdata module after the changes introduced by #15298:
# get_config_vars() is called by get_platform() as part of the
# _sysconfigdata module manually and populate it with the build vars.
# This is more than sufficient for ensuring the subsequent call to
# get_platform() succeeds.
- name = _get_sysconfigdata_name()
- if 'darwin' in sys.platform:
- import types
- module = types.ModuleType(name)
- module.build_time_vars = vars
- sys.modules[name] = module
+ # GH-127178: Since we started generating a .json file, we also need this to
+ # be able to run sysconfig.get_config_vars().
+ module = types.ModuleType(name)
+ module.build_time_vars = vars
+ sys.modules[name] = module
- pybuilddir = f'build/lib.{get_platform()}-{get_python_version()}'
- if hasattr(sys, "gettotalrefcount"):
- pybuilddir += '-pydebug'
+ pybuilddir = _get_pybuilddir()
os.makedirs(pybuilddir, exist_ok=True)
destfile = os.path.join(pybuilddir, name + '.py')
f.write('build_time_vars = ')
_print_config_dict(vars, stream=f)
+ # Write a JSON file with the output of sysconfig.get_config_vars
+ jsonfile = os.path.join(pybuilddir, _get_json_data_name())
+ with open(jsonfile, 'w') as f:
+ json.dump(get_config_vars(), f, indent=2)
+
# Create file used for sys.path fixup -- see Modules/getpath.c
with open('pybuilddir.txt', 'w', encoding='utf8') as f:
f.write(pybuilddir)
from test.support import (
captured_stdout,
+ is_android,
is_apple_mobile,
is_wasi,
PythonSymlink,
from sysconfig import (get_paths, get_platform, get_config_vars,
get_path, get_path_names, _INSTALL_SCHEMES,
get_default_scheme, get_scheme_names, get_config_var,
- _expand_vars, _get_preferred_schemes)
-from sysconfig.__main__ import _main, _parse_makefile
+ _expand_vars, _get_preferred_schemes,
+ is_python_build, _PROJECT_BASE)
+from sysconfig.__main__ import _main, _parse_makefile, _get_pybuilddir, _get_json_data_name
import _imp
import _osx_support
import _sysconfig
def setUp(self):
super(TestSysConfig, self).setUp()
+ self.maxDiff = None
self.sys_path = sys.path[:]
# patching os.uname
if hasattr(os, 'uname'):
self.assertNotEqual(data['prefix'], data['base_prefix'])
self.assertNotEqual(data['exec_prefix'], data['base_exec_prefix'])
+ @unittest.skipIf(os.name != 'posix', '_sysconfig-vars JSON file is only available on POSIX')
+ @unittest.skipIf(is_wasi, "_sysconfig-vars JSON file currently isn't available on WASI")
+ @unittest.skipIf(is_android or is_apple_mobile, 'Android and iOS change the prefix')
+ def test_sysconfigdata_json(self):
+ if '_PYTHON_SYSCONFIGDATA_PATH' in os.environ:
+ data_dir = os.environ['_PYTHON_SYSCONFIGDATA_PATH']
+ elif is_python_build():
+ data_dir = os.path.join(_PROJECT_BASE, _get_pybuilddir())
+ else:
+ data_dir = sys._stdlib_dir
+
+ json_data_path = os.path.join(data_dir, _get_json_data_name())
+
+ with open(json_data_path) as f:
+ json_config_vars = json.load(f)
+
+ system_config_vars = get_config_vars()
+
+ # Ignore keys in the check
+ for key in ('projectbase', 'srcdir'):
+ json_config_vars.pop(key)
+ system_config_vars.pop(key)
+
+ self.assertEqual(system_config_vars, json_config_vars)
+
+
class MakefileTests(unittest.TestCase):
@unittest.skipIf(sys.platform.startswith('win'),
esac; \
done; \
done
- $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py \
- $(DESTDIR)$(LIBDEST); \
+ $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py $(DESTDIR)$(LIBDEST); \
+ $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfig_vars_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).json $(DESTDIR)$(LIBDEST); \
$(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt
@ # If app store compliance has been configured, apply the patch to the
@ # installed library code. The patch has been previously validated against
--- /dev/null
+A ``_sysconfig_vars_(...).json`` file is now shipped in the standard library
+directory. It contains the output of :func:`sysconfig.get_config_vars` on
+the default environment encoded as JSON data. This is an implementation
+detail, and may change at any time.