Skip to content

Commit 87b4cee

Browse files
committed
ENH: add support for removing build time RPATH entries
Requires Meson 1.9.0.
1 parent b572d71 commit 87b4cee

4 files changed

Lines changed: 36 additions & 15 deletions

File tree

docs/reference/meson-compatibility.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ versions.
6161

6262
Meson 1.9.0 or later is required to support building for iOS.
6363

64+
Meson 1.9.0 or later is also required to remove RPATH entries that
65+
are added by Meson to allow to execute parts of the project from
66+
the build directory and that are normally removed during ``meson
67+
install``. On older Meson versions, these entries are not removed,
68+
but this should not have any adverse effect.
69+
6470
Build front-ends by default build packages in an isolated Python
6571
environment where build dependencies are installed. Most often, unless
6672
a package or its build dependencies declare explicitly a version

mesonpy/__init__.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ class _Entry(typing.NamedTuple):
129129
# list to store install RPATH to be able to add append more
130130
# entries when needed.
131131
install_rpath: List[str] = []
132+
# RPATH entries to remove at install time.
133+
build_rpath: List[str] = []
132134

133135

134136
def _map_to_wheel(
@@ -188,7 +190,8 @@ def _map_to_wheel(
188190
wheel_files[path].append(_Entry(filedst, filesrc))
189191
else:
190192
install_rpath = target.get('install_rpath')
191-
wheel_files[path].append(_Entry(dst, src, [install_rpath] if install_rpath else []))
193+
build_rpath = target.get('build_rpaths')
194+
wheel_files[path].append(_Entry(dst, src, [install_rpath] if install_rpath else [], build_rpath or []))
192195

193196
return wheel_files
194197

@@ -454,15 +457,16 @@ def _stable_abi(self) -> Optional[str]:
454457
return 'abi3.abi3t' if abi3t else 'abi3'
455458
return None
456459

457-
def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, destination: pathlib.Path,
458-
install_rpath: List[str]) -> None:
460+
def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile,
461+
origin: Path, destination: pathlib.Path,
462+
install_rpath: List[str], build_rpath: List[str]) -> None:
459463
"""Add a file to the wheel."""
460464

461465
if self._has_internal_libs and _is_native(origin):
462466
libspath = os.path.relpath(self._libs_dir, destination.parent)
463-
mesonpy._rpath.fix_rpath(origin, install_rpath, libspath)
464-
elif install_rpath:
465-
mesonpy._rpath.fix_rpath(origin, install_rpath, None)
467+
mesonpy._rpath.fix_rpath(origin, install_rpath, build_rpath, libspath)
468+
elif install_rpath or build_rpath:
469+
mesonpy._rpath.fix_rpath(origin, install_rpath, build_rpath, None)
466470

467471
try:
468472
wheel_file.write(origin, destination.as_posix())
@@ -506,7 +510,7 @@ def build(self, directory: Path) -> pathlib.Path:
506510
root = 'purelib' if self._pure else 'platlib'
507511

508512
for path, entries in self._manifest.items():
509-
for dst, src, install_rpath in entries:
513+
for dst, src, install_rpath, build_rpath in entries:
510514
counter.update(src)
511515

512516
if path == root:
@@ -517,7 +521,7 @@ def build(self, directory: Path) -> pathlib.Path:
517521
else:
518522
dst = pathlib.Path(self._data_dir, path, dst)
519523

520-
self._install_path(whl, src, dst, install_rpath)
524+
self._install_path(whl, src, dst, install_rpath, build_rpath)
521525

522526
return wheel_file
523527

mesonpy/_rpath.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@ def set_rpath(filepath: Path, old: List[str], rpath: List[str]) -> None:
3737
raise NotImplementedError
3838

3939
@classmethod
40-
def fix_rpath(cls, filepath: Path, install_rpath: List[str], libs_relative_path: Optional[str]) -> None:
40+
def fix_rpath(cls, filepath: Path, add: List[str], remove: List[str], libs_relative_path: Optional[str]) -> None:
4141
old_rpath = cls.get_rpath(filepath)
42-
new_rpath = old_rpath[:]
42+
43+
# Meson adds a padding entry to RPATH composed of enough `X`
44+
# characters to reserve enough space in the ELF header to hold
45+
# the final installation RPATH. Remove this entry and other
46+
# entries to be removed.
47+
new_rpath = [path for path in old_rpath if path.strip('X') and path not in remove]
4348

4449
# When an executable, libray, or Python extension module is
4550
# dynamically linked to a library built as part of the project, Meson
@@ -55,7 +60,7 @@ def fix_rpath(cls, filepath: Path, install_rpath: List[str], libs_relative_path:
5560
new_rpath.append(os.path.join(cls.origin, libs_relative_path))
5661

5762
# Add install_rpath.
58-
new_rpath += install_rpath
63+
new_rpath += add
5964

6065
new_rpath = unique(new_rpath)
6166
if new_rpath != old_rpath:
@@ -65,7 +70,7 @@ def fix_rpath(cls, filepath: Path, install_rpath: List[str], libs_relative_path:
6570
class _Windows(RPATH):
6671

6772
@classmethod
68-
def fix_rpath(cls, filepath: Path, install_rpath: List[str], libs_relative_path: str) -> None:
73+
def fix_rpath(cls, filepath: Path, add: List[str], remove: List[str], libs_relative_path: Optional[str]) -> None:
6974
pass
7075

7176

tests/test_wheel.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
INTERPRETER = tag.interpreter
4444
PLATFORM = adjust_packaging_platform_tag(tag.platform)
4545

46+
# Support for removing build RPATH entries requires Meson 1.9 or later.
47+
BUILD_RPATH_SUPPORT = MESON_VERSION >= (1, 9)
48+
4649

4750
def wheel_contents(artifact):
4851
# Sometimes directories have entries, sometimes not, so we filter them out.
@@ -186,12 +189,14 @@ def test_sharedlib_in_package_rpath(wheel_sharedlib_in_package, tmp_path):
186189
origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN'
187190

188191
rpath = set(mesonpy._rpath.get_rpath(tmp_path / 'mypkg' / f'_example{EXT_SUFFIX}'))
189-
# FIXME: RPATH entries added by Meson to point to the build directory are not removed.
190192
assert rpath >= {origin}
193+
if BUILD_RPATH_SUPPORT:
194+
assert rpath == {origin}
191195

192196
rpath = set(mesonpy._rpath.get_rpath(tmp_path / 'mypkg' / f'liblib{LIB_SUFFIX}'))
193-
# FIXME: RPATH entries added by Meson to point to the build directory are not removed.
194197
assert rpath >= {f'{origin}/sub'}
198+
if BUILD_RPATH_SUPPORT:
199+
assert rpath == {f'{origin}/sub'}
195200

196201
rpath = set(mesonpy._rpath.get_rpath(tmp_path / 'mypkg' / 'sub' / f'libsublib{LIB_SUFFIX}'))
197202
assert rpath == set()
@@ -235,8 +240,9 @@ def test_link_against_local_lib_rpath(wheel_link_against_local_lib, tmp_path):
235240
expected = {f'{origin}/../.link_against_local_lib.mesonpy.libs', 'custom-rpath',}
236241

237242
rpath = set(mesonpy._rpath.get_rpath(tmp_path / 'example' / f'_example{EXT_SUFFIX}'))
238-
# FIXME: RPATH entries added by Meson to point to the build directory are not removed.
239243
assert rpath >= expected
244+
if BUILD_RPATH_SUPPORT:
245+
assert rpath == expected
240246

241247

242248
@pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support')

0 commit comments

Comments
 (0)