11# "Benedikt Hegner (CERN)"
2+ # "Patrick Gartung (FNAL)"
23
34import os
45import stat
1011import llnl .util .tty as tty
1112
1213
13- def get_existing_rpath (path_name , patchelf_executable ):
14+ def get_existing_elf_rpaths (path_name , old_dir , new_dir ):
1415 """
15- Return the RPATHS in given file as a list of strings.
16+ Return the RPATHS in given elf file as a list of strings.
1617 """
17- if platform .system () == 'Darwin' :
18- command = which ('otool' )
19- output = command ("-l" , path_name , output = str , err = str )
20- if command .returncode != 0 :
21- tty .warn ('failed reading rpath for %s.' % path_name )
22- return False
23- last_cmd = None
24- path = set ()
25- for line in output .split ('\n ' ):
26- match = re .search ('( *[a-zA-Z]+ )(.*)' , line )
27- if match :
28- lhs = match .group (1 ).lstrip ().rstrip ()
29- rhs = match .group (2 )
30- match2 = re .search ('(.*) \(.*\)' , rhs )
31- if match2 :
32- rhs = match2 .group (1 )
33- if lhs == 'cmd' :
34- last_cmd = rhs
35- if lhs == 'path' and last_cmd == 'LC_RPATH' :
36- path .add (rhs )
37- return path
38- elif platform .system () == 'Linux' :
18+ if platform .system () == 'Linux' :
3919 command = '%s --print-rpath %s ' % (patchelf_executable , path_name )
4020 status , output = getstatusoutput (command )
4121 if status != 0 :
@@ -46,17 +26,42 @@ def get_existing_rpath(path_name, patchelf_executable):
4626 tty .die ('relocation not supported for this platform' )
4727 return retval
4828
49- def change_dylib (path_name , rpaths ):
29+ def modify_macho_object (path_name , old_dir , new_dir ):
5030 """
51- Return the RPATHS in given file as a list of strings.
31+ Modify MachO binaries by changing rpaths,and id and dependency lib paths.
32+
33+ Examines the output of otool -l for these three patterns
34+
35+ cmd LC_ID_DYLIB
36+ cmdsize 160
37+ name /Users/gartung/spack-macdev/opt/spack/darwin-x86_64/clang-7.0.2-apple/tcl-8.6.5-xfeydlhaojmei6iws2rnxndvriym242k/lib/libtcl8.6.dylib (offset 24)
38+
39+ cmd LC_LOAD_DYLIB
40+ cmdsize 160
41+ name /Users/gartung/spack-macdev/opt/spack/darwin-x86_64/clang-7.0.2-apple/zlib-1.2.8-cyvcqvrzlgurne424y55hxvfucvz2354/lib/libz.1.dylib (offset 24)
42+
43+ cmd LC_RPATH
44+ cmdsize 128
45+ path /Users/gartung/spack-macdev/opt/spack/darwin-x86_64/clang-7.0.2-apple/xz-5.2.2-d4ecxpuzf2g3ycz3cnj3xmdj7zdnuqwb/lib (offset 12)
46+
47+ the old install dir in LC_LOAD_DYLIB is replace with the new install dir using
48+ install_name_tool -id newid binary
49+
50+ the old install dir in LC_LOAD_DYLIB is replaced with the new install dir using
51+ install_name_tool -change old new binary
52+
53+ the old install dir in LC_RPATH is replaced with the new install dir using
54+ install_name_tool -rpath old new binary
55+
5256 """
5357 command = which ('otool' )
5458 output = command ("-l" , path_name , output = str , err = str )
5559 if command .returncode != 0 :
5660 tty .warn ('failed reading rpath for %s.' % path_name )
5761 return False
5862 last_cmd = None
59- path = ''
63+ idpath = ''
64+ rpaths = []
6065 deps = []
6166 for line in output .split ('\n ' ):
6267 match = re .search ('( *[a-zA-Z]+ )(.*)' , line )
@@ -68,19 +73,21 @@ def change_dylib(path_name, rpaths):
6873 rhs = match2 .group (1 )
6974 if lhs == 'cmd' :
7075 last_cmd = rhs
76+ if lhs == 'path' and last_cmd == 'LC_RPATH' :
77+ rpaths .append (rhs )
7178 if lhs == 'name' and last_cmd == 'LC_ID_DYLIB' :
72- path = rhs
79+ idpath = rhs
7380 if lhs == 'name' and last_cmd == 'LC_LOAD_DYLIB' :
7481 deps .append (rhs )
75- id = path
82+ id = idpath . replace ( old_dir , new_dir )
7683 ndeps = []
84+ nrpaths = []
7785 for rpath in rpaths :
78- if re . match ( rpath , path ):
79- id = '@rpath' + re . split ( rpath , path )[ 1 ]
86+ nrpath = rpath . replace ( old_dir , new_dir )
87+ nrpaths . append ( nrpath )
8088 for dep in deps :
81- if re .match (rpath ,dep ):
82- ndep = '@rpath' + re .split (rpath ,dep )[1 ]
83- ndeps .append (ndep )
89+ ndep = dep .replace (old_dir ,new_dir )
90+ ndeps .append (ndep )
8491
8592 st = os .stat (path_name )
8693 wmode = os .access (path_name , os .W_OK )
@@ -93,13 +100,23 @@ def change_dylib(path_name, rpaths):
93100 if status != 0 :
94101 tty .warn ('failed writing id for %s.' % path_name )
95102 tty .warn (output )
103+
96104 for orig , new in zip (deps , ndeps ):
97105 command = ("install_name_tool -change %s %s %s" %
98106 (orig , new , path_name ))
99107 status , output = getstatusoutput (command )
100108 if status != 0 :
101109 tty .warn ('failed writing dep for %s.' % path_name )
102110 tty .warn (output )
111+
112+ for orig , new in zip (rpaths , nrpaths ):
113+ command = ("install_name_tool -rpath %s %s %s" %
114+ (orig ,new ,path_name ) )
115+ status , output = getstatusoutput (command )
116+ if status != 0 :
117+ tty .warn ('failed writing id for %s.' % path_name )
118+ tty .warn (output )
119+
103120 os .chmod (path_name , st .st_mode )
104121 return
105122
@@ -117,25 +134,15 @@ def get_filetype(path_name):
117134 return output .strip ()
118135
119136
120- def modify_rpath (path_name , orig_rpath , new_rpath , patchelf_executable ):
137+ def modify_elf_object (path_name , orig_rpath , new_rpath , patchelf_executable ):
121138 """
122- Replace RPATH in given binary
139+ Replace RPATH's in given elf object
123140 """
124141 st = os .stat (path_name )
125142 wmode = os .access (path_name , os .W_OK )
126143 if not wmode :
127144 os .chmod (path_name , st .st_mode | stat .S_IWUSR )
128- if platform .system () == 'Darwin' :
129- for orig , new in zip (orig_rpath , new_rpath ):
130- command = which ("install_name_tool" )
131- output = command ("-rpath" , "%s" % orig ,
132- "%s" % new ,
133- "%s" % path_name ,
134- output = str ,
135- err = str )
136- if command .returncode != 0 :
137- tty .warn ('failed writing rpath for %s.' % path_name )
138- elif platform .system () == 'Linux' :
145+ if platform .system () == 'Linux' :
139146 new_joined = ':' .join (new_rpath )
140147 command = "%s --force-rpath --set-rpath '%s' '%s'" % \
141148 (patchelf_executable , new_joined , path_name )
@@ -172,13 +179,16 @@ def needs_text_relocation(filetype):
172179
173180def relocate_binary (path_name , old_dir , new_dir , patchelf_executable ):
174181 """
175- Change RPATHs in given file
182+ Change RPATHs in given elf or mach-o file
176183 """
177- orig_rpath = get_existing_rpath (path_name , patchelf_executable )
178- new_rpath = substitute_rpath (orig_rpath , old_dir , new_dir )
179- modify_rpath (path_name , orig_rpath , new_rpath , patchelf_executable )
180184 if platform .system () == 'Darwin' :
181- change_dylib (path_name , orig_rpath )
185+ modify_macho_object (path_name , old_dir , new_dir )
186+ elif platform .system () == 'Linux' :
187+ orig_rpaths = get_existing_elf_rpaths (path_name , patchelf_executable )
188+ new_rpaths = substitute_rpath (orig_rpath , old_dir , new_dir )
189+ modify_elf_object (path_name , orig_rpaths , new_rpaths , patchelf_executable )
190+ else :
191+ tty .die ("Relocation not implemented for %s" % platform .system ())
182192
183193
184194def relocate_text (path_name , old_dir , new_dir ):
0 commit comments