Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,12 @@ Build changes

(Contributed by Stefano Rivera in :gh:`131372`.)

* The paths in the installed ``build-details.json`` file (:pep:`739`) are
now relative to the file's location instead of absolute, so the file stays
correct when the installation is moved.

(Contributed by Itamar Oren in :gh:`119696`.)

* Add the :option:`--with-curses` :program:`configure` option to select the
curses backend for the :mod:`curses` and :mod:`curses.panel` modules.
In addition to ``ncursesw`` and ``ncurses``, it can now build against the
Expand Down
48 changes: 29 additions & 19 deletions Lib/test/test_build_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,32 @@ def contents(self):
with open(self.location, 'r', encoding='utf-8') as f:
return f.read()

def resolve(self, value):
"""Resolve a path from the file, as a PEP 739 consumer would."""
base_prefix = os.path.join(os.path.dirname(self.location),
self.key('base_prefix'))
return os.path.normpath(os.path.join(base_prefix, value))

@needs_installed_python
def test_location(self):
self.assertTrue(os.path.isfile(self.location))

@needs_installed_python
def test_paths_are_relative(self):
self.assertFalse(os.path.isabs(self.key('base_prefix')))
self.assertEqual(os.path.realpath(self.resolve('.')),
os.path.realpath(sys.base_prefix))

for name in ('base_interpreter', 'libpython.dynamic',
'libpython.dynamic_stableabi', 'libpython.static',
'c_api.headers', 'c_api.pkgconfig_path'):
with self.subTest(key=name):
try:
value = self.key(name)
except KeyError:
continue
self.assertFalse(os.path.isabs(value))

# Override generic format tests with tests for our specific implemenation.

@needs_installed_python
Expand All @@ -150,11 +172,7 @@ def test_location(self):
'Android and iOS run tests via a custom testbed method that changes sys.executable'
)
def test_base_interpreter(self):
value = self.key('base_interpreter')

# Skip check if installation is relocated
if sysconfig._installation_is_relocated():
self.skipTest("Installation is relocated")
value = self.resolve(self.key('base_interpreter'))

self.assertEqual(os.path.realpath(value), os.path.realpath(sys.executable))

Expand All @@ -166,13 +184,11 @@ def test_base_interpreter(self):
def test_c_api(self):
value = self.key('c_api')

# Skip check if installation is relocated
if sysconfig._installation_is_relocated():
self.skipTest("Installation is relocated")

self.assertTrue(os.path.exists(os.path.join(value['headers'], 'Python.h')))
headers = self.resolve(value['headers'])
self.assertTrue(os.path.exists(os.path.join(headers, 'Python.h')))
version = sysconfig.get_config_var('VERSION')
self.assertTrue(os.path.exists(os.path.join(value['pkgconfig_path'], f'python-{version}.pc')))
pkgconfig_path = self.resolve(value['pkgconfig_path'])
self.assertTrue(os.path.exists(os.path.join(pkgconfig_path, f'python-{version}.pc')))

@needs_installed_python
@unittest.skipIf(
Expand All @@ -184,11 +200,8 @@ def test_libpython_static(self):
if 'static' not in value:
self.skipTest("No static libpython")

if sysconfig._installation_is_relocated():
self.skipTest("Installation is relocated")

# The path must name an installed static library (an 'ar' archive).
with open(value['static'], 'rb') as f:
with open(self.resolve(value['static']), 'rb') as f:
self.assertEqual(f.read(8), b'!<arch>\n')

@needs_installed_python
Expand All @@ -206,10 +219,7 @@ def test_libpython_dynamic(self):
if 'dynamic' not in value:
self.skipTest("No dynamic libpython")

if sysconfig._installation_is_relocated():
self.skipTest("Installation is relocated")

self.assertTrue(os.path.isfile(value['dynamic']))
self.assertTrue(os.path.isfile(self.resolve(value['dynamic'])))


@unittest.skipIf(
Expand Down
4 changes: 3 additions & 1 deletion Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,9 @@ pybuilddir.txt: $(PYTHON_FOR_BUILD_DEPS)
fi

$(BUILD_DETAILS): pybuilddir.txt
$(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/build/generate-build-details.py `cat pybuilddir.txt`/$(BUILD_DETAILS)
$(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/build/generate-build-details.py \
--relative-paths --config-file-path "$(LIBDEST)/$(BUILD_DETAILS)" \
`cat pybuilddir.txt`/$(BUILD_DETAILS)

# Build static library
$(LIBRARY): $(LIBRARY_OBJS)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The paths in the installed ``build-details.json`` file (:pep:`739`) are now
relative to the file's location instead of absolute, so the file stays
correct when the installation is moved.