mirror of
https://github.com/mpv-player/mpv
synced 2024-12-26 09:02:38 +00:00
e3972746dc
since the loading order of rpaths is system wide lib path, dev tool path and then bundle lib path it's possible for the xcode swift libs to be incompatible with the libs the bundle was build with. this leads to possible segfaults. if we distribute the bundle we don't want to load the libs from the dev tools anyway.
145 lines
4.7 KiB
Python
Executable File
145 lines
4.7 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import re
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import subprocess
|
|
from functools import partial
|
|
|
|
sys_re = re.compile("^/System")
|
|
usr_re = re.compile("^/usr/lib/")
|
|
exe_re = re.compile("@executable_path")
|
|
|
|
def is_user_lib(objfile, libname):
|
|
return not sys_re.match(libname) and \
|
|
not usr_re.match(libname) and \
|
|
not exe_re.match(libname) and \
|
|
not "libobjc." in libname and \
|
|
not "libSystem." in libname and \
|
|
not "libc." in libname and \
|
|
not "libgcc." in libname and \
|
|
not os.path.basename(libname) == 'Python' and \
|
|
not os.path.basename(objfile) in libname and \
|
|
not "libswift" in libname
|
|
|
|
def otool(objfile):
|
|
command = "otool -L '%s' | grep -e '\t' | awk '{ print $1 }'" % objfile
|
|
output = subprocess.check_output(command, shell = True, universal_newlines=True)
|
|
return set(filter(partial(is_user_lib, objfile), output.split()))
|
|
|
|
def get_rpaths_dev_tools(binary):
|
|
command = "otool -l '%s' | grep -A2 LC_RPATH | grep path | grep \"Xcode\|CommandLineTools\"" % binary
|
|
result = subprocess.check_output(command, shell = True, universal_newlines=True)
|
|
pathRe = re.compile("^\s*path (.*) \(offset \d*\)$")
|
|
output = []
|
|
|
|
for line in result.splitlines():
|
|
output.append(pathRe.search(line).group(1).strip())
|
|
|
|
return output
|
|
|
|
def install_name_tool_change(old, new, objfile):
|
|
subprocess.call(["install_name_tool", "-change", old, new, objfile])
|
|
|
|
def install_name_tool_id(name, objfile):
|
|
subprocess.call(["install_name_tool", "-id", name, objfile])
|
|
|
|
def install_name_tool_add_rpath(rpath, binary):
|
|
subprocess.call(["install_name_tool", "-add_rpath", rpath, binary])
|
|
|
|
def install_name_tool_delete_rpath(rpath, binary):
|
|
subprocess.call(["install_name_tool", "-delete_rpath", rpath, binary])
|
|
|
|
def libraries(objfile, result = dict()):
|
|
libs_list = otool(objfile)
|
|
result[objfile] = libs_list
|
|
|
|
for lib in libs_list:
|
|
if lib not in result:
|
|
libraries(lib, result)
|
|
|
|
return result
|
|
|
|
def leafs(libs_dict, processed = []):
|
|
result = []
|
|
processed = set(processed)
|
|
|
|
for objfile, libs in libs_dict.items():
|
|
if libs <= processed:
|
|
result.append(objfile)
|
|
|
|
return result
|
|
|
|
def lib_path(binary):
|
|
return os.path.join(os.path.dirname(binary), 'lib')
|
|
|
|
def lib_name(lib):
|
|
return os.path.join("@executable_path", "lib", os.path.basename(lib))
|
|
|
|
def process_libraries(libs_dict, binary, processed = []):
|
|
ls = leafs(libs_dict, processed)
|
|
diff = set(ls) - set(processed)
|
|
if diff == set([binary]):
|
|
return
|
|
|
|
for src in diff:
|
|
name = lib_name(src)
|
|
dst = os.path.join(lib_path(binary), os.path.basename(src))
|
|
|
|
shutil.copy(src, dst)
|
|
os.chmod(dst, 0o755)
|
|
install_name_tool_id(name, dst)
|
|
|
|
if src in libs_dict[binary]:
|
|
install_name_tool_change(src, name, binary)
|
|
|
|
for p in processed:
|
|
if p in libs_dict[src]:
|
|
install_name_tool_change(p, lib_name(p), dst)
|
|
|
|
return ls
|
|
|
|
def process_swift_libraries(binary):
|
|
command = ['xcrun', '--find', 'swift-stdlib-tool']
|
|
swiftStdlibTool = subprocess.check_output(command, universal_newlines=True).strip()
|
|
# from xcode11 on the dynamic swift libs reside in a separate directory from
|
|
# the std one, might need versioned paths for future swift versions
|
|
swiftLibPath = os.path.join(swiftStdlibTool, '../../lib/swift-5.0/macosx')
|
|
swiftLibPath = os.path.abspath(swiftLibPath)
|
|
|
|
command = [swiftStdlibTool, '--copy', '--platform', 'macosx', '--scan-executable', binary, '--destination', lib_path(binary)]
|
|
|
|
if os.path.exists(swiftLibPath):
|
|
command.extend(['--source-libraries', swiftLibPath])
|
|
|
|
subprocess.check_output(command, universal_newlines=True)
|
|
|
|
print(">> setting additional rpath for swift libraries")
|
|
install_name_tool_add_rpath("@executable_path/lib", binary)
|
|
|
|
def remove_dev_tools_rapths(binary):
|
|
for path in get_rpaths_dev_tools(binary):
|
|
install_name_tool_delete_rpath(path, binary)
|
|
|
|
def main():
|
|
binary = os.path.abspath(sys.argv[1])
|
|
if not os.path.exists(lib_path(binary)):
|
|
os.makedirs(lib_path(binary))
|
|
print(">> gathering all linked libraries")
|
|
libs = libraries(binary)
|
|
|
|
print(">> copying and processing all linked libraries")
|
|
libs_processed = process_libraries(libs, binary)
|
|
while libs_processed is not None:
|
|
libs_processed = process_libraries(libs, binary, libs_processed)
|
|
|
|
print(">> removing rpath definitions towards dev tools")
|
|
remove_dev_tools_rapths(binary)
|
|
|
|
print(">> copying and processing swift libraries")
|
|
process_swift_libraries(binary)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|