1111
1212
1313if typing .TYPE_CHECKING :
14- from typing import List
14+ from typing import List , TypeVar
1515
16- from mesonpy ._compat import Iterable , Path
16+ from mesonpy ._compat import Path
1717
18+ T = TypeVar ('T' )
1819
19- if sys .platform == 'win32' or sys .platform == 'cygwin' :
2020
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 :
2258 pass
2359
24- elif sys .platform == 'darwin' :
2560
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 ]:
2767 rpath = []
2868 r = subprocess .run (['otool' , '-l' , os .fspath (filepath )], capture_output = True , text = True )
2969 rpath_tag = False
@@ -35,17 +75,24 @@ def _get_rpath(filepath: Path) -> List[str]:
3575 rpath_tag = False
3676 return rpath
3777
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 )
4090
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 )
4591
46- elif sys . platform == 'sunos5' :
92+ class _SunOS5 ( RPATH ) :
4793
48- def _get_rpath (filepath : Path ) -> List [str ]:
94+ @staticmethod
95+ def get_rpath (filepath : Path ) -> List [str ]:
4996 rpath = []
5097 r = subprocess .run (['/usr/bin/elfedit' , '-r' , '-e' , 'dyn:rpath' , os .fspath (filepath )],
5198 capture_output = True , check = True , text = True )
@@ -56,35 +103,32 @@ def _get_rpath(filepath: Path) -> List[str]:
56103 rpath .append (path )
57104 return rpath
58105
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 :
60108 subprocess .run (['/usr/bin/elfedit' , '-e' , 'dyn:rpath ' + ':' .join (rpath ), os .fspath (filepath )], check = True )
61109
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 )
71110
72- else :
73- # Assume that any other platform uses ELF binaries.
111+ class _ELF (RPATH ):
74112
75- def _get_rpath (filepath : Path ) -> List [str ]:
113+ @staticmethod
114+ def get_rpath (filepath : Path ) -> List [str ]:
76115 r = subprocess .run (['patchelf' , '--print-rpath' , os .fspath (filepath )], capture_output = True , text = True )
77116 return [x for x in r .stdout .strip ().split (':' ) if x ]
78117
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 :
80120 subprocess .run (['patchelf' ,'--set-rpath' , ':' .join (rpath ), os .fspath (filepath )], check = True )
81121
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