|
@@ -1,86 +1,47 @@
|
|
|
-
|
|
|
-
|
|
|
-import hashlib
|
|
|
-import optparse
|
|
|
-import ConfigParser
|
|
|
-import os
|
|
|
-import platform
|
|
|
-import subprocess
|
|
|
+from pathlib import Path
|
|
|
import sys
|
|
|
+import argparse
|
|
|
+from collections import deque
|
|
|
+import subprocess
|
|
|
import shutil
|
|
|
|
|
|
-exts = (".dylib", ".so")
|
|
|
-exes = ("fc-cache", "macdeployqt", "qmake", "moc", "rcc", "qmlimportscanner", "QtWebEngineProcess")
|
|
|
-
|
|
|
-def exec_cmd(args, env={}, supress_output=False):
|
|
|
- cmd = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, env = env)
|
|
|
- output = ''
|
|
|
- while True:
|
|
|
- out = cmd.stdout.read(1)
|
|
|
- if out == '' and cmd.poll() != None:
|
|
|
- break
|
|
|
- if out != '':
|
|
|
- if not supress_output:
|
|
|
- sys.stdout.write(out)
|
|
|
- output += out
|
|
|
- if cmd.wait() != 0:
|
|
|
- raise Exception("Command failed: \"%s\"" % " ".join(args), output)
|
|
|
- return output
|
|
|
-
|
|
|
-def fix_install_name(path):
|
|
|
- for root, dirs, files in os.walk(path):
|
|
|
- for f in files:
|
|
|
- fpath = os.path.join(root, f)
|
|
|
-
|
|
|
- if os.path.basename(f) == "QtWebEngineProcess":
|
|
|
- print "-- Adding rpath (%s) to %s" % (os.path.join(path, "lib"), f)
|
|
|
- exec_cmd(["install_name_tool", "-add_rpath", os.path.join(path, "lib"), fpath], supress_output=True)
|
|
|
-
|
|
|
- if (f.endswith(exts) or os.path.basename(f) in exes or (".framework/Versions/" in root and os.access(fpath, os.X_OK))) and not os.path.islink(fpath) and os.path.exists(fpath):
|
|
|
-
|
|
|
- if not os.access(fpath, os.W_OK) or not os.access(fpath, os.R_OK) or not os.access(fpath, os.X_OK):
|
|
|
- os.chmod(fpath, 0o644)
|
|
|
-
|
|
|
- try:
|
|
|
- basename = os.path.basename(fpath)
|
|
|
- otoolout = exec_cmd(["otool", "-L", fpath], supress_output=True)
|
|
|
-
|
|
|
- for l in otoolout.split("\n")[1:]:
|
|
|
- l = l.rstrip().strip()
|
|
|
-
|
|
|
-
|
|
|
- if len(l) > 0 and (l.startswith("/Volumes/CI-OSX/") or (l[0] != '/' and not l.startswith("@rpath"))):
|
|
|
- current_lib = l.split(" (compat")[0]
|
|
|
- current_basename = os.path.basename(current_lib)
|
|
|
- correct_lib = os.path.join(root, current_basename)
|
|
|
-
|
|
|
- if ".framework" in current_lib:
|
|
|
- current_basename = "/".join(current_lib.split("/")[-4:])
|
|
|
-
|
|
|
- if not os.path.exists(correct_lib):
|
|
|
-
|
|
|
- if os.path.exists(os.path.join(path, "lib", current_basename)):
|
|
|
- correct_lib = os.path.join(path, "lib", current_basename)
|
|
|
- elif os.path.exists(os.path.join(path, "lib", current_lib)):
|
|
|
- correct_lib = os.path.join(path, "lib", current_lib)
|
|
|
- else:
|
|
|
- print "Can't link %s" % current_lib
|
|
|
- continue
|
|
|
-
|
|
|
-
|
|
|
- if current_lib != correct_lib:
|
|
|
- if current_basename.split('.')[0] == basename.split('.')[0]:
|
|
|
- print "-- Fixing ID for", basename
|
|
|
- exec_cmd(["install_name_tool", "-id", correct_lib, fpath], supress_output=True)
|
|
|
- else:
|
|
|
- print "-- Fixing library link for %s (%s)" % (basename, current_basename)
|
|
|
- exec_cmd(["install_name_tool", "-change", current_lib, correct_lib, fpath], supress_output=True)
|
|
|
-
|
|
|
- except:
|
|
|
- print "** Fail when running installname on %s" % f
|
|
|
- raise
|
|
|
- continue
|
|
|
|
|
|
-if __name__=='__main__':
|
|
|
- if os.path.isdir(sys.argv[1]):
|
|
|
- fix_install_name(sys.argv[1])
|
|
|
+def main(argv=tuple(sys.argv[1:])):
|
|
|
+ arg_parser = argparse.ArgumentParser(description='Fix third party library paths in .app bundles.')
|
|
|
+ arg_parser.add_argument('bundle', metavar='BUNDLE', type=str, nargs=1)
|
|
|
+ arguments = arg_parser.parse_args(argv)
|
|
|
+
|
|
|
+ bundle_path = Path(arguments.bundle[0])
|
|
|
+ framework_path = bundle_path / 'Contents' / 'Frameworks'
|
|
|
+ framework_libs = set(file.name for file in framework_path.glob('*.dylib')).union(set(file.name for file in framework_path.glob('*.so')))
|
|
|
+ libs_to_fix = deque()
|
|
|
+ libs_to_fix.extend(file for file in bundle_path.glob('**/*.dylib'))
|
|
|
+ libs_to_fix.extend(file for file in bundle_path.glob('**/*.so'))
|
|
|
+ while libs_to_fix:
|
|
|
+ lib = libs_to_fix.popleft()
|
|
|
+
|
|
|
+ result = subprocess.check_output(['otool', '-L', str(lib.resolve())], stderr=subprocess.STDOUT).decode('utf-8')
|
|
|
+ for dependency in result.splitlines():
|
|
|
+ dependency = dependency.strip().lstrip()
|
|
|
+ if dependency.startswith('/usr/local'):
|
|
|
+
|
|
|
+ dependency = Path(dependency.split(' (compatibility')[0])
|
|
|
+
|
|
|
+
|
|
|
+ if dependency.name not in framework_libs:
|
|
|
+ shutil.copy(str(dependency.resolve()), str(framework_path.resolve()))
|
|
|
+ framework_libs.add(dependency.name)
|
|
|
+
|
|
|
+ libs_to_fix.append(framework_path / dependency.name)
|
|
|
+ print((framework_path / dependency.name).resolve())
|
|
|
+ print(f'Copied {dependency} to {framework_path / dependency.name}')
|
|
|
+
|
|
|
+
|
|
|
+ target = f'@executable_path/../Frameworks/{dependency.name}'
|
|
|
+ print(f'Fixing dependency {dependency} of {lib} to {target}')
|
|
|
+ subprocess.run(['install_name_tool', '-id', target, lib])
|
|
|
+ subprocess.run(['install_name_tool', '-change', str(dependency), target, lib])
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ main()
|