68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
import subprocess
|
|
import sys
|
|
from os.path import join, basename
|
|
import os
|
|
|
|
app_bundle = sys.argv[1]
|
|
dry_run = '--dry' in sys.argv
|
|
|
|
app_binary = join(app_bundle, 'Contents/MacOS', basename(app_bundle).split(".")[0])
|
|
app_frameworks = join(app_bundle, 'Contents/Frameworks')
|
|
|
|
binaries_unfiltered = [app_binary] + [join(app_frameworks, library) for library in os.listdir(app_frameworks)]
|
|
binaries = []
|
|
# Extend .framework paths to the actual binary
|
|
for binary in binaries_unfiltered:
|
|
if binary.endswith('.framework'):
|
|
binaries.append(join(binary, 'Versions/A/' + basename(binary).split(".")[0]))
|
|
else:
|
|
binaries.append(binary)
|
|
|
|
dependency_map = {binary:subprocess.check_output(["otool", "-L", binary], text=True).splitlines()[1:] for binary in binaries}
|
|
|
|
for binary, dependencies in dependency_map.items():
|
|
print(binary)
|
|
|
|
is_framework = '.framework' in binary
|
|
if binary == app_binary:
|
|
# check if a new rpath is needed
|
|
new_rpath = '@loader_path/../Frameworks'
|
|
|
|
has_rpath = False
|
|
lines = reversed(subprocess.check_output(["otool", "-l", binary], text=True).splitlines())
|
|
for line in lines:
|
|
if line.strip().startswith('path '):
|
|
existing_rpath = line.strip()[len('path '):line.strip().find('(') - 1]
|
|
if existing_rpath == new_rpath:
|
|
has_rpath = True
|
|
else:
|
|
break
|
|
if not has_rpath:
|
|
print('\tAdding rpath: ' + new_rpath)
|
|
if not dry_run:
|
|
print('\t' + subprocess.check_output(['install_name_tool', '-add_rpath', new_rpath, binary], text=True))
|
|
for dependency in dependencies:
|
|
end_index = dependency.index('(')
|
|
dep = dependency[0:end_index].strip()
|
|
|
|
dep_short_name = dep[dep.rfind('/')+1:]
|
|
if '.framework' in dep:
|
|
index = dep.find('.framework')
|
|
dep_short_name = dep[dep.rfind('/', 0, index)+1:]
|
|
|
|
if dep == binary or basename(dep_short_name) == basename(binary):
|
|
continue
|
|
for key in dependency_map:
|
|
if key.endswith(dep_short_name):
|
|
if binary == app_binary:
|
|
print(f'\t{dep} -> @rpath/{dep_short_name}')
|
|
if not dry_run:
|
|
print('\t' + subprocess.check_output(['install_name_tool', '-change', dep, f'@rpath/{dep_short_name}', binary], text=True))
|
|
else:
|
|
new_path = f'@loader_path/{dep_short_name}'
|
|
if is_framework:
|
|
new_path = f'@loader_path/../../../{dep_short_name}'
|
|
print(f'\t{dep} -> {new_path}')
|
|
if not dry_run:
|
|
print('\t' + subprocess.check_output(['install_name_tool', '-change', dep, new_path, binary], text=True))
|
|
break |