Skip to content

Commit 89aee9c

Browse files
committed
ENH: correctly handle install_rpath when installing into wheels
Fixes #711.
1 parent 8b61d26 commit 89aee9c

File tree

2 files changed

+52
-13
lines changed

2 files changed

+52
-13
lines changed

mesonpy/__init__.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class InvalidLicenseExpression(Exception): # type: ignore[no-redef]
113113
class Entry(typing.NamedTuple):
114114
dst: pathlib.Path
115115
src: str
116+
rpath: Optional[List[str]] = None
116117

117118

118119
def _map_to_wheel(sources: Dict[str, Dict[str, Any]]) -> DefaultDict[str, List[Entry]]:
@@ -161,7 +162,7 @@ def _map_to_wheel(sources: Dict[str, Dict[str, Any]]) -> DefaultDict[str, List[E
161162
filedst = dst / relpath
162163
wheel_files[path].append(Entry(filedst, filesrc))
163164
else:
164-
wheel_files[path].append(Entry(dst, src))
165+
wheel_files[path].append(Entry(dst, src, target.get('install_rpath')))
165166

166167
return wheel_files
167168

@@ -420,7 +421,8 @@ def _stable_abi(self) -> Optional[str]:
420421
return 'abi3'
421422
return None
422423

423-
def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, destination: pathlib.Path) -> None:
424+
def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile,
425+
origin: Path, destination: pathlib.Path, rpath: Optional[List[str]]) -> None:
424426
"""Add a file to the wheel."""
425427

426428
if self._has_internal_libs:
@@ -438,7 +440,12 @@ def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path,
438440
# relocates the shared libraries to the $project.mesonpy.libs
439441
# folder. Rewrite the RPATH to point to that folder instead.
440442
libspath = os.path.relpath(self._libs_dir, destination.parent)
441-
mesonpy._rpath.fix_rpath(origin, libspath)
443+
rpath = rpath or []
444+
rpath.append(libspath)
445+
446+
# Apply RPATH as per above and any ``install_rpath`` specified in meson.build
447+
if rpath:
448+
mesonpy._rpath.fix_rpath(origin, rpath)
442449

443450
try:
444451
wheel_file.write(origin, destination.as_posix())
@@ -476,7 +483,7 @@ def build(self, directory: Path) -> pathlib.Path:
476483
root = 'purelib' if self._pure else 'platlib'
477484

478485
for path, entries in self._manifest.items():
479-
for dst, src in entries:
486+
for dst, src, rpath in entries:
480487
counter.update(src)
481488

482489
if path == root:
@@ -487,7 +494,7 @@ def build(self, directory: Path) -> pathlib.Path:
487494
else:
488495
dst = pathlib.Path(self._data_dir, path, dst)
489496

490-
self._install_path(whl, src, dst)
497+
self._install_path(whl, src, dst, rpath)
491498

492499
return wheel_file
493500

mesonpy/_rpath.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,28 @@
99
import sys
1010
import typing
1111

12+
from itertools import chain
13+
1214

1315
if typing.TYPE_CHECKING:
14-
from typing import List
16+
from typing import List, TypeVar
1517

1618
from mesonpy._compat import Iterable, Path
1719

20+
T = TypeVar('T')
21+
22+
23+
def unique(values: List[T]) -> List[T]:
24+
r = []
25+
for value in values:
26+
if value not in r:
27+
r.append(value)
28+
return r
29+
1830

1931
if sys.platform == 'win32' or sys.platform == 'cygwin':
2032

21-
def fix_rpath(filepath: Path, libs_relative_path: str) -> None:
33+
def fix_rpath(filepath: Path, rpath: List[str]) -> None:
2234
pass
2335

2436
elif sys.platform == 'darwin':
@@ -35,13 +47,27 @@ def _get_rpath(filepath: Path) -> List[str]:
3547
rpath_tag = False
3648
return rpath
3749

38-
def _replace_rpath(filepath: Path, old: str, new: str) -> None:
39-
subprocess.run(['install_name_tool', '-rpath', old, new, os.fspath(filepath)], check=True)
50+
def _delete_rpath(filepath: Path, paths: List[str]) -> None:
51+
args = chain(*(('-delete_rpath', path) for path in paths))
52+
subprocess.run(['install_name_tool', *args, os.fspath(filepath)], check=True)
4053

54+
def _add_rpath(filepath: Path, paths: List[str]) -> None:
55+
args = chain(*(('-add_rpath', path) for path in paths))
56+
subprocess.run(['install_name_tool', *args, os.fspath(filepath)], check=True)
57+
4158
def fix_rpath(filepath: Path, libs_relative_path: str) -> None:
42-
for path in _get_rpath(filepath):
59+
old_rpath = _get_rpath(filepath)
60+
new_rpath = []
61+
for path in old_rpath:
4362
if path.startswith('@loader_path/'):
44-
_replace_rpath(filepath, path, '@loader_path/' + libs_relative_path)
63+
path = '$ORIGIN/' + libs_relative_path
64+
new_rpath.append(path)
65+
if rpath:
66+
new_rpath.extend(rpath)
67+
new_rpath = unique(rpath)
68+
if new_rpath != old_rpath:
69+
_delete_rpath(old_rpath)
70+
_add_rpath(new_rpath)
4571

4672
elif sys.platform == 'sunos5':
4773

@@ -59,13 +85,16 @@ def _get_rpath(filepath: Path) -> List[str]:
5985
def _set_rpath(filepath: Path, rpath: Iterable[str]) -> None:
6086
subprocess.run(['/usr/bin/elfedit', '-e', 'dyn:rpath ' + ':'.join(rpath), os.fspath(filepath)], check=True)
6187

62-
def fix_rpath(filepath: Path, libs_relative_path: str) -> None:
88+
def fix_rpath(filepath: Path, rpath: str) -> None:
6389
old_rpath = _get_rpath(filepath)
6490
new_rpath = []
6591
for path in old_rpath:
6692
if path.startswith('$ORIGIN/'):
6793
path = '$ORIGIN/' + libs_relative_path
6894
new_rpath.append(path)
95+
if rpath:
96+
new_rpath.extend(rpath)
97+
new_rpath = unique(rpath)
6998
if new_rpath != old_rpath:
7099
_set_rpath(filepath, new_rpath)
71100

@@ -79,12 +108,15 @@ def _get_rpath(filepath: Path) -> List[str]:
79108
def _set_rpath(filepath: Path, rpath: Iterable[str]) -> None:
80109
subprocess.run(['patchelf','--set-rpath', ':'.join(rpath), os.fspath(filepath)], check=True)
81110

82-
def fix_rpath(filepath: Path, libs_relative_path: str) -> None:
111+
def fix_rpath(filepath: Path, rpath: str) -> None:
83112
old_rpath = _get_rpath(filepath)
84113
new_rpath = []
85114
for path in old_rpath:
86115
if path.startswith('$ORIGIN/'):
87116
path = '$ORIGIN/' + libs_relative_path
88117
new_rpath.append(path)
118+
if rpath:
119+
new_rpath.extend(rpath)
120+
new_rpath = unique(rpath)
89121
if new_rpath != old_rpath:
90122
_set_rpath(filepath, new_rpath)

0 commit comments

Comments
 (0)