11
11
12
12
13
13
if typing .TYPE_CHECKING :
14
- from typing import List
14
+ from typing import List , TypeVar
15
15
16
- from mesonpy ._compat import Iterable , Path
16
+ from mesonpy ._compat import Path
17
17
18
+ T = TypeVar ('T' )
18
19
19
- if sys .platform == 'win32' or sys .platform == 'cygwin' :
20
20
21
- def fix_rpath (filepath : Path , libs_relative_path : str ) -> None :
21
+ def unique (values : List [T ]) -> List [T ]:
22
+ r = []
23
+ for value in values :
24
+ if value not in r :
25
+ r .append (value )
26
+ return r
27
+
28
+
29
+ class RPATH :
30
+
31
+ origin = '$ORIGIN'
32
+
33
+ @staticmethod
34
+ def get_rpath (filepath : Path ) -> List [str ]:
35
+ raise NotImplementedError
36
+
37
+ @staticmethod
38
+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
39
+ raise NotImplementedError
40
+
41
+ @classmethod
42
+ def fix_rpath (cls , filepath : Path , libs_relative_path : str ) -> None :
43
+ old_rpath = cls .get_rpath (filepath )
44
+ new_rpath = []
45
+ for path in old_rpath :
46
+ if path .startswith (cls .origin ):
47
+ path = os .path .join (cls .origin , libs_relative_path )
48
+ new_rpath .append (path )
49
+ new_rpath = unique (new_rpath )
50
+ if new_rpath != old_rpath :
51
+ cls .set_rpath (filepath , old_rpath , new_rpath )
52
+
53
+
54
+ class _Windows (RPATH ):
55
+
56
+ @classmethod
57
+ def fix_rpath (cls , filepath : Path , libs_relative_path : str ) -> None :
22
58
pass
23
59
24
- elif sys .platform == 'darwin' :
25
60
26
- def _get_rpath (filepath : Path ) -> List [str ]:
61
+ class _MacOS (RPATH ):
62
+
63
+ origin = '@loader_path'
64
+
65
+ @staticmethod
66
+ def get_rpath (filepath : Path ) -> List [str ]:
27
67
rpath = []
28
68
r = subprocess .run (['otool' , '-l' , os .fspath (filepath )], capture_output = True , text = True )
29
69
rpath_tag = False
@@ -35,17 +75,24 @@ def _get_rpath(filepath: Path) -> List[str]:
35
75
rpath_tag = False
36
76
return rpath
37
77
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 )
78
+ @staticmethod
79
+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
80
+ # This implementation does not preserve the ordering of RPATH
81
+ # entries. Meson does the same, thus it should not be a problem.
82
+ args : List [str ] = []
83
+ for path in rpath :
84
+ if path not in old :
85
+ args += ['-add_rpath' , path ]
86
+ for path in old :
87
+ if path not in rpath :
88
+ args += ['-delete_rpath' , path ]
89
+ subprocess .run (['install_name_tool' , * args , os .fspath (filepath )], check = True )
40
90
41
- def fix_rpath (filepath : Path , libs_relative_path : str ) -> None :
42
- for path in _get_rpath (filepath ):
43
- if path .startswith ('@loader_path/' ):
44
- _replace_rpath (filepath , path , '@loader_path/' + libs_relative_path )
45
91
46
- elif sys . platform == 'sunos5' :
92
+ class _SunOS5 ( RPATH ) :
47
93
48
- def _get_rpath (filepath : Path ) -> List [str ]:
94
+ @staticmethod
95
+ def get_rpath (filepath : Path ) -> List [str ]:
49
96
rpath = []
50
97
r = subprocess .run (['/usr/bin/elfedit' , '-r' , '-e' , 'dyn:rpath' , os .fspath (filepath )],
51
98
capture_output = True , check = True , text = True )
@@ -56,35 +103,32 @@ def _get_rpath(filepath: Path) -> List[str]:
56
103
rpath .append (path )
57
104
return rpath
58
105
59
- def _set_rpath (filepath : Path , rpath : Iterable [str ]) -> None :
106
+ @staticmethod
107
+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
60
108
subprocess .run (['/usr/bin/elfedit' , '-e' , 'dyn:rpath ' + ':' .join (rpath ), os .fspath (filepath )], check = True )
61
109
62
- def fix_rpath (filepath : Path , libs_relative_path : str ) -> None :
63
- old_rpath = _get_rpath (filepath )
64
- new_rpath = []
65
- for path in old_rpath :
66
- if path .startswith ('$ORIGIN/' ):
67
- path = '$ORIGIN/' + libs_relative_path
68
- new_rpath .append (path )
69
- if new_rpath != old_rpath :
70
- _set_rpath (filepath , new_rpath )
71
110
72
- else :
73
- # Assume that any other platform uses ELF binaries.
111
+ class _ELF (RPATH ):
74
112
75
- def _get_rpath (filepath : Path ) -> List [str ]:
113
+ @staticmethod
114
+ def get_rpath (filepath : Path ) -> List [str ]:
76
115
r = subprocess .run (['patchelf' , '--print-rpath' , os .fspath (filepath )], capture_output = True , text = True )
77
116
return [x for x in r .stdout .strip ().split (':' ) if x ]
78
117
79
- def _set_rpath (filepath : Path , rpath : Iterable [str ]) -> None :
118
+ @staticmethod
119
+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
80
120
subprocess .run (['patchelf' ,'--set-rpath' , ':' .join (rpath ), os .fspath (filepath )], check = True )
81
121
82
- def fix_rpath (filepath : Path , libs_relative_path : str ) -> None :
83
- old_rpath = _get_rpath (filepath )
84
- new_rpath = []
85
- for path in old_rpath :
86
- if path .startswith ('$ORIGIN/' ):
87
- path = '$ORIGIN/' + libs_relative_path
88
- new_rpath .append (path )
89
- if new_rpath != old_rpath :
90
- _set_rpath (filepath , new_rpath )
122
+
123
+ if sys .platform == 'win32' or sys .platform == 'cygwin' :
124
+ _cls = _Windows
125
+ elif sys .platform == 'darwin' :
126
+ _cls = _MacOS
127
+ elif sys .platform == 'sunos5' :
128
+ _cls = _SunOS5
129
+ else :
130
+ _cls = _ELF
131
+
132
+ get_rpath = _cls .get_rpath
133
+ set_rpath = _cls .set_rpath
134
+ fix_rpath = _cls .fix_rpath
0 commit comments