Skip to content

Commit

Permalink
Prevent adding duplicate rpaths to bundled libs
Browse files Browse the repository at this point in the history
  • Loading branch information
ianrrees committed Jan 23, 2016
1 parent 27fbcca commit 45d343e
Showing 1 changed file with 49 additions and 14 deletions.
63 changes: 49 additions & 14 deletions src/Tools/MakeMacBundleRelocatable.py
@@ -1,7 +1,8 @@
import os
import sys
import subprocess
from subprocess import Popen, PIPE, check_call, check_output
import pprint
import re

SYS_PATHS = ["/System/", "/usr/lib/"]

Expand Down Expand Up @@ -63,8 +64,9 @@ def visit(self, operation, op_args=[]):
stack.append(ck)
operation(self, self.graph[node_key], *op_args)


def is_macho(path):
output = subprocess.check_output(["file", path])
output = check_output(["file", path])
if output.count("Mach-O") != 0:
return True

Expand All @@ -83,7 +85,7 @@ def get_path(name, search_paths):
return None

def list_install_names(path_macho):
output = subprocess.check_output(["otool", "-L", path_macho])
output = check_output(["otool", "-L", path_macho])
lines = output.split("\t")
libs = []

Expand Down Expand Up @@ -129,7 +131,7 @@ def create_dep_nodes(install_names, search_paths):
path = get_path(lib_name, search_paths)

if install_path != "" and lib[0] != "@":
#we have an absolte path install name
#we have an absolute path install name
if not path:
path = install_path

Expand All @@ -148,7 +150,6 @@ def paths_at_depth(prefix, paths, depth):
filtered.append(p)
return filtered


def should_visit(prefix, path_filters, path):
s_path = path.strip('/').split('/')
filters = []
Expand Down Expand Up @@ -227,14 +228,44 @@ def in_bundle(lib, bundle_path):

def copy_into_bundle(graph, node, bundle_path):
if not in_bundle(node.path, bundle_path):
subprocess.check_call(["cp", "-L", os.path.join(node.path, node.name),
os.path.join(bundle_path, "lib", node.name)])
check_call([ "cp", "-L", os.path.join(node.path, node.name),
os.path.join(bundle_path, "lib", node.name) ])

node.path = os.path.join(bundle_path, "lib")

#fix permissions
subprocess.check_call(["chmod", "a+w", os.path.join(bundle_path,
"lib", node.name)])

check_call([ "chmod", "a+w",
os.path.join(bundle_path, "lib", node.name) ])

def get_rpaths(library):
"Returns a list of rpaths specified within library"

out = check_output(["otool", "-l", library])

pathRegex = r"^path (.*) \(offset \d+\)$"
expectingRpath = False
rpaths = []
for line in out.split('\n'):
line = line.strip()

if "cmd LC_RPATH" in line:
expectingRpath = True
continue

if "Load command" in line:
expectingRpath = False
continue

if not expectingRpath:
continue

m = re.match(pathRegex, line)
if m:
rpaths.append(m.group(1))
expectingRpath = False

return rpaths

def add_rpaths(graph, node, bundle_path):
if node.children:
lib = os.path.join(node.path, node.name)
Expand All @@ -245,8 +276,8 @@ def add_rpaths(graph, node, bundle_path):
for install_name in install_names:
name = os.path.basename(install_name)
#change install names to use rpaths
subprocess.check_call(["install_name_tool", "-change",
install_name, "@rpath/" + name, lib])
check_call([ "install_name_tool", "-change",
install_name, "@rpath/" + name, lib ])

dep_node = node.children[node.children.index(name)]
rel_path = os.path.relpath(graph.get_node(dep_node).path,
Expand All @@ -258,8 +289,12 @@ def add_rpaths(graph, node, bundle_path):
rpath = "@loader_path/" + rel_path + "/"
if rpath not in rpaths:
rpaths.append(rpath)
for path in rpaths:
subprocess.call(["install_name_tool", "-add_rpath", path, lib])

for rpath in rpaths:
# Ensure that lib has rpath set
if not rpath in get_rpaths(lib):
check_output([ "install_name_tool",
"-add_rpath", rpath, lib ])

def main():
if len(sys.argv) < 2:
Expand Down

0 comments on commit 45d343e

Please sign in to comment.