-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmatryoshka_name_tool.py
More file actions
85 lines (74 loc) · 3.55 KB
/
matryoshka_name_tool.py
File metadata and controls
85 lines (74 loc) · 3.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/opt/local/bin/python
#coding: utf-8
__author__ = 'stsmith'
# matryoshka_name_tool: recursive copy and apply install_name_tool to .dylib's
# Copyright 2015 Steven T. Smith <steve dot t dot smith at gmail dot com>, GPL
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse as ap, errno, os, re, shutil, subprocess as sp
import traceback
def make_sure_empty_path_exists(path):
try:
shutil.rmtree(path)
except OSError as exception:
if exception.errno != errno.ENOENT:
raise
try:
os.makedirs(path)
except OSError as exception:
if exception.errno != errno.EEXIST:
raise
class MatryoshkaName:
args = None
def run(self):
self.args = self.parseArgs()
self.libdir_pattern = re.compile(r'^\s+' + self.args.libdir)
self.dylib_pattern = re.compile(r'^\s+(%s.+?) .+' % self.args.libdir)
if not self.args.update:
make_sure_empty_path_exists(self.args.install_libdir)
self.dylibs_copied = set()
self.dylibs_recursed = set()
for object in self.args.objects: self.install_name_tool(object)
def parseArgs(self):
parser = ap.ArgumentParser()
parser.add_argument('objects', metavar='OBJS', type=str, nargs='+',
help='Object file[s]')
parser.add_argument('-d', '--install-libdir', help="Shared library install directory", type=str, default='../lib/')
parser.add_argument('-L', '--libdir', help="Shared library source directory", type=str, default='/opt/local/lib/')
parser.add_argument('-u', '--update', help="Update the install directory", action='store_true')
return parser.parse_args()
def install_name_tool(self,object):
p = sp.Popen(['otool', '-L', object], stdout=sp.PIPE)
out, err = p.communicate()
lines = out.splitlines()
for line in lines[1:]:
if self.libdir_pattern.match(line):
dylib = self.dylib_pattern.sub(r'\1',line)
if dylib not in self.dylibs_copied:
if not self.args.update and not os.path.isfile(self.args.install_libdir + os.path.basename(dylib)):
shutil.copy(dylib, self.args.install_libdir)
self.dylibs_copied.add(dylib)
target = self.args.install_libdir + os.path.basename(object) \
if (os.path.splitext(os.path.basename(object))[1] == '.dylib') \
else object
cmd = [ 'install_name_tool', '-change', dylib,
'@executable_path/' + self.args.install_libdir + os.path.basename(dylib),
target ]
sp.call(cmd)
print "\t" + ' '.join(cmd)
if dylib not in self.dylibs_recursed and dylib != object: # recurse
self.install_name_tool(dylib)
self.dylibs_recursed.add(dylib)
if __name__ == "__main__":
install_name = MatryoshkaName()
install_name.run()