1313if typing .TYPE_CHECKING :
1414 from typing import List
1515
16- from mesonpy ._compat import Iterable , Path
16+ from mesonpy ._compat import Path
1717
1818
19- if sys .platform == 'win32' or sys .platform == 'cygwin' :
19+ def unique (values : List [T ]) -> List [T ]:
20+ r = []
21+ for value in values :
22+ if value not in r :
23+ r .append (value )
24+ return r
25+
26+
27+ class RPATH :
28+
29+ origin = '$ORIGIN'
30+
31+ @staticmethod
32+ def get_rpath (filepath : Path ) -> List [str ]:
33+ raise NotImplementedError
34+
35+ @staticmethod
36+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
37+ raise NotImplementedError
38+
39+ @classmethod
40+ def fix_rpath (cls , filepath : Path , libs_relative_path : str ) -> None :
41+ old_rpath = cls .get_rpath (filepath )
42+ new_rpath = []
43+ for path in old_rpath :
44+ if path .startswith (cls .origin ):
45+ path = os .path .join (cls .origin , libs_relative_path )
46+ new_rpath .append (path )
47+ new_rpath = unique (new_rpath )
48+ if new_rpath != old_rpath :
49+ cls .set_rpath (filepath , old_rpath , new_rpath )
50+
2051
21- def fix_rpath (filepath : Path , libs_relative_path : str ) -> None :
52+ class _Windows (RPATH ):
53+
54+ @classmethod
55+ def fix_rpath (cls , filepath : Path , libs_relative_path : str ) -> None :
2256 pass
2357
24- elif sys .platform == 'darwin' :
2558
26- def _get_rpath (filepath : Path ) -> List [str ]:
59+ class _MacOS (RPATH ):
60+
61+ origin = '@loader_path'
62+
63+ @staticmethod
64+ def get_rpath (filepath : Path ) -> List [str ]:
2765 rpath = []
2866 r = subprocess .run (['otool' , '-l' , os .fspath (filepath )], capture_output = True , text = True )
2967 rpath_tag = False
@@ -35,17 +73,24 @@ def _get_rpath(filepath: Path) -> List[str]:
3573 rpath_tag = False
3674 return rpath
3775
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 )
76+ @staticmethod
77+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
78+ # This implementation does not preserve the ordering of RPATH
79+ # entries. Meson does the same, thus it should not be a problem.
80+ args : List [str ] = []
81+ for path in rpath :
82+ if path not in old :
83+ args += ['-add_rpath' , path ]
84+ for path in old :
85+ if path not in rpath :
86+ args += ['-delete_rpath' , path ]
87+ subprocess .run (['install_name_tool' , * args , os .fspath (filepath )], check = True )
4088
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 )
4589
46- elif sys . platform == 'sunos5' :
90+ class _SunOS5 ( RPATH ) :
4791
48- def _get_rpath (filepath : Path ) -> List [str ]:
92+ @staticmethod
93+ def get_rpath (filepath : Path ) -> List [str ]:
4994 rpath = []
5095 r = subprocess .run (['/usr/bin/elfedit' , '-r' , '-e' , 'dyn:rpath' , os .fspath (filepath )],
5196 capture_output = True , check = True , text = True )
@@ -56,35 +101,32 @@ def _get_rpath(filepath: Path) -> List[str]:
56101 rpath .append (path )
57102 return rpath
58103
59- def _set_rpath (filepath : Path , rpath : Iterable [str ]) -> None :
104+ @staticmethod
105+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
60106 subprocess .run (['/usr/bin/elfedit' , '-e' , 'dyn:rpath ' + ':' .join (rpath ), os .fspath (filepath )], check = True )
61107
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 )
71108
72- else :
73- # Assume that any other platform uses ELF binaries.
109+ class _ELF (RPATH ):
74110
75- def _get_rpath (filepath : Path ) -> List [str ]:
111+ @staticmethod
112+ def get_rpath (filepath : Path ) -> List [str ]:
76113 r = subprocess .run (['patchelf' , '--print-rpath' , os .fspath (filepath )], capture_output = True , text = True )
77114 return [x for x in r .stdout .strip ().split (':' ) if x ]
78115
79- def _set_rpath (filepath : Path , rpath : Iterable [str ]) -> None :
116+ @staticmethod
117+ def set_rpath (filepath : Path , old : List [str ], rpath : List [str ]) -> None :
80118 subprocess .run (['patchelf' ,'--set-rpath' , ':' .join (rpath ), os .fspath (filepath )], check = True )
81119
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 )
120+
121+ if sys .platform == 'win32' or sys .platform == 'cygwin' :
122+ _cls = _Windows
123+ elif sys .platform == 'darwin' :
124+ _cls = _MacOS
125+ elif sys .platform == 'sunos5' :
126+ _cls = _SunOS
127+ else :
128+ _cls = _ELF
129+
130+ get_rpath = _cls .get_rpath
131+ set_rpath = _cls .set_rpath
132+ fix_rpath = _cls .fix_rpath
0 commit comments