Skip to content

Commit 45d04fd

Browse files
committed
Implement linux
Signed-off-by: Cristian Le <[email protected]>
1 parent c3ed941 commit 45d04fd

File tree

1 file changed

+65
-3
lines changed
  • src/scikit_build_core/repair_wheel

1 file changed

+65
-3
lines changed

src/scikit_build_core/repair_wheel/linux.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44

55
from __future__ import annotations
66

7+
import os.path
8+
from pathlib import Path
79
from typing import TYPE_CHECKING
810

9-
import auditwheel # noqa: F401
11+
from auditwheel.elfutils import elf_read_rpaths
12+
from auditwheel.patcher import Patchelf
1013

14+
from .._logging import logger
1115
from . import WheelRepairer
1216

1317
if TYPE_CHECKING:
@@ -23,6 +27,64 @@ class LinuxWheelRepairer(WheelRepairer):
2327

2428
_platform = "Linux"
2529

30+
def patch_linux_library_rpath(self, lib: Path, rpaths: list[str]) -> None:
31+
"""Patch the rpaths of a specific library."""
32+
# Flatten the current rpaths
33+
curr_rpaths = {
34+
path for dt_rpaths in elf_read_rpaths(lib).values() for path in dt_rpaths
35+
}
36+
final_rpaths = set()
37+
# Patch pre-existing rpaths
38+
for rpath_str in curr_rpaths:
39+
# If the rpath is already relative keep it
40+
if rpath_str.startswith("$ORIGIN"):
41+
final_rpaths.add(rpath_str)
42+
continue
43+
# Otherwise check if we need to patch it
44+
rpath_path = Path(rpath_str)
45+
try:
46+
rpath_path.relative_to(self.install_dir)
47+
except ValueError:
48+
# If it does not point to wheel install path, just keep it
49+
final_rpaths.add(rpath_str)
50+
continue
51+
# Otherwise change the RPATH to point use $ORIGIN
52+
new_rpath = os.path.relpath(rpath_str, lib.parent)
53+
new_rpath = f"$ORIGIN/{new_rpath}"
54+
final_rpaths.add(new_rpath)
55+
# Merge with all the rpaths we were given
56+
final_rpaths = final_rpaths.union(rpaths)
57+
patcher = Patchelf()
58+
patcher.set_rpath(lib, ":".join(final_rpaths))
59+
2660
def patch_target(self, target: Target) -> None:
27-
# TODO: Implement patching
28-
pass
61+
# Get the target install paths where the $ORIGIN is calculated from
62+
target_install_paths = self.get_wheel_install_paths(target)
63+
if not target_install_paths:
64+
logger.debug(
65+
"Skip patching {target} because all install paths are outside the wheel.",
66+
target=target.name,
67+
)
68+
return
69+
if len(set(target.artifacts)) != 1:
70+
logger.warning(
71+
"Unexpected multiple artifacts for target {target}: {artifacts}",
72+
target=target.name,
73+
artifacts=[item.path for item in target.artifacts],
74+
)
75+
return
76+
artifact = target.artifacts[0]
77+
for install_path in target_install_paths:
78+
target_path = self.install_dir / install_path
79+
dependency_rpaths = []
80+
for dep_target in self.get_library_dependencies(target):
81+
dep_install_paths = self.get_wheel_install_paths(dep_target)
82+
assert len(dep_install_paths) == 1
83+
dep_path = self.install_dir / next(iter(dep_install_paths))
84+
rpath = os.path.relpath(dep_path, target_path)
85+
rpath = f"$ORIGIN/{rpath}"
86+
dependency_rpaths.append(rpath)
87+
self.patch_linux_library_rpath(
88+
lib=target_path / artifact.path,
89+
rpaths=dependency_rpaths,
90+
)

0 commit comments

Comments
 (0)