Skip to content

Instantly share code, notes, and snippets.

@h0tw1r3
Last active September 18, 2015 05:47
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save h0tw1r3/b12752f8e33f70422fbe to your computer and use it in GitHub Desktop.
Recursively change dynamic library link paths for non-system libraries to be relative to the linked program and copy them to <program>/../libs. I use this in a cross-compile environment on linux.
#!/usr/bin/env python
# coding: utf-8
# Recursively change dynamic library link paths for non-system libraries
# to be relative to the linked program and copy them to <program>/../libs
#
# TODO: parse individual architectures (ever necessary?)
# modify temp lib instead of assuming path changes work
#
# Copyright: © 2015 Jeffrey Clark
# License: GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html)
import os, stat, sys, subprocess, re, shutil
otool = os.getenv('TOOLCHAIN','') + "otool"
if toolchain == None:
toolchain = ""
else:
toolchain += "-"
otool = toolchain + "otool"
install_name_tool = toolchain + "install_name_tool"
def runOtool(filename):
p = subprocess.Popen([otool, '-XL', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return iter(p.stdout.readline, b'')
def fixname(filename, old, new):
p = subprocess.Popen([install_name_tool, '-change', old, new, filename], stdout=subprocess.PIPE)
p.communicate()
return
def fixid(filename, newid):
p = subprocess.Popen([install_name_tool, '-id', '@loader_path/../libs/' + newid, filename], stdout=subprocess.PIPE)
p.communicate()
return
def cmd_exists(cmd):
return subprocess.call("type " + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0
def mainloop(filename):
for line in runOtool(filename):
m = re.search('\s+/((usr|opt)/local/.*) \(.*\)$', line)
if m and len(m.group(1)) != 0:
path = os.path.realpath( os.path.join(os.getenv('LIB_BASE_PATH','/'),m.group(1)) )
linkname = os.path.basename( path )
if os.path.isfile( '../libs/' + linkname ) is False:
try:
shutil.copy2(path, '../libs/')
os.chmod('../libs/' + linkname, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH )
fixid('../libs/' + linkname, linkname)
mainloop('../libs/' + linkname)
except IOError as e:
print e
continue
fixname( filename, '/' + m.group(1), '@loader_path/../libs/' + linkname )
else:
m = re.search('\s+(@rpath(.*)) \(.*\)$', line)
if m and len(m.group(2)) != 0:
path = os.path.realpath(os.path.join(os.getenv('LIB_BASE_PATH','/'), 'usr/local/lib', m.group(2)))
print path
linkname = os.path.basename(path)
fixname(filename, m.group(1), '@loader_path/../libs/' + linkname)
if (len(sys.argv) != 2):
print "Usage: " + os.path.basename(sys.argv[0]) + " executable"
sys.exit(1)
if (not cmd_exists(otool)):
raise ValueError('Unable to execute otool: ' + otool)
if (not cmd_exists(install_name_tool)):
raise ValueError('Unable to execute install_name_tool: ' + install_name_tool)
if (not os.path.isfile(sys.argv[1])):
raise ValueError('File does not exist: ' + sys.argv[1])
if (not os.access(sys.argv[1], os.W_OK)):
raise ValueError('Unable to write to file: ' + sys.argv[1])
mainloop(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment