diff options
Diffstat (limited to '')
-rwxr-xr-x | TOOLS/dylib_unhell.py (renamed from TOOLS/dylib-unhell.py) | 101 |
1 files changed, 94 insertions, 7 deletions
diff --git a/TOOLS/dylib-unhell.py b/TOOLS/dylib_unhell.py index c41d200..c885969 100755 --- a/TOOLS/dylib-unhell.py +++ b/TOOLS/dylib_unhell.py @@ -5,6 +5,7 @@ import os import sys import shutil import subprocess +import json from functools import partial sys_re = re.compile("^/System") @@ -41,7 +42,7 @@ def otool(objfile, rapths): def get_rapths(objfile): rpaths = [] command = "otool -l '%s' | grep -A2 LC_RPATH | grep path" % objfile - pathRe = re.compile("^\s*path (.*) \(offset \d*\)$") + pathRe = re.compile(r"^\s*path (.*) \(offset \d*\)$") try: result = subprocess.check_output(command, shell = True, universal_newlines=True) @@ -49,14 +50,19 @@ def get_rapths(objfile): return rpaths for line in result.splitlines(): - rpaths.append(pathRe.search(line).group(1).strip()) + line_clean = pathRe.search(line).group(1).strip() + # resolve @loader_path + if line_clean.startswith('@loader_path/'): + line_clean = line_clean[len('@loader_path/'):] + line_clean = os.path.normpath(os.path.join(os.path.dirname(objfile), line_clean)) + rpaths.append(line_clean) return rpaths def get_rpaths_dev_tools(binary): - command = "otool -l '%s' | grep -A2 LC_RPATH | grep path | grep \"Xcode\|CommandLineTools\"" % 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*\)$") + pathRe = re.compile(r"^\s*path (.*) \(offset \d*\)$") output = [] for line in result.splitlines(): @@ -82,6 +88,23 @@ def resolve_lib_path(objfile, lib, rapths): raise Exception('Could not resolve library: ' + lib) +def check_vulkan_max_version(version): + try: + result = subprocess.check_output("pkg-config vulkan --max-version=" + version, shell = True) + return True + except: + return False + +def get_homebrew_prefix(): + # set default to standard ARM path, intel path is already in the vulkan loader search array + result = "/opt/homebrew" + try: + result = subprocess.check_output("brew --prefix", universal_newlines=True, shell=True, stderr=subprocess.DEVNULL).strip() + except: + pass + + return result + def install_name_tool_change(old, new, objfile): subprocess.call(["install_name_tool", "-change", old, new, objfile], stderr=subprocess.DEVNULL) @@ -109,6 +132,9 @@ def libraries(objfile, result = dict(), result_relative = set(), rapths = []): def lib_path(binary): return os.path.join(os.path.dirname(binary), 'lib') +def resources_path(binary): + return os.path.join(os.path.dirname(binary), '../Resources') + def lib_name(lib): return os.path.join("@executable_path", "lib", os.path.basename(lib)) @@ -157,12 +183,68 @@ def process_swift_libraries(binary): print(">> setting additional rpath for swift libraries") install_name_tool_add_rpath("@executable_path/lib", binary) +def process_vulkan_loader(binary, loaderName, loaderRelativeFolder, libraryNode): + # https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderDriverInterface.md#example-macos-driver-search-path + # https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderLayerInterface.md#macos-layer-discovery + loaderSystemSearchFolders = [ + os.path.join(os.path.expanduser("~"), ".config", loaderRelativeFolder), + os.path.join("/etc/xdg", loaderRelativeFolder), + os.path.join("/usr/local/etc", loaderRelativeFolder), + os.path.join("/etc", loaderRelativeFolder), + os.path.join(os.path.expanduser("~"), ".local/share", loaderRelativeFolder), + os.path.join("/usr/local/share", loaderRelativeFolder), + os.path.join("/usr/share/vulkan", loaderRelativeFolder), + os.path.join(get_homebrew_prefix(), 'share', loaderRelativeFolder), + ] + + loaderSystemFolder = "" + for loaderSystemSearchFolder in loaderSystemSearchFolders: + if os.path.exists(loaderSystemSearchFolder): + loaderSystemFolder = loaderSystemSearchFolder + break + + if not loaderSystemFolder: + print(">>> could not find loader folder " + loaderRelativeFolder) + return + + loaderBundleFolder = os.path.join(resources_path(binary), loaderRelativeFolder) + loaderSystemPath = os.path.join(loaderSystemFolder, loaderName) + loaderBundlePath = os.path.join(loaderBundleFolder, loaderName) + libraryRelativeFolder = "../../../Frameworks/" + + if not os.path.exists(loaderSystemPath): + print(">>> could not find loader " + loaderName) + return + + if not os.path.exists(loaderBundleFolder): + os.makedirs(loaderBundleFolder) + + loaderSystemFile = open(loaderSystemPath, 'r') + loaderJsonData = json.load(loaderSystemFile) + librarySystemPath = os.path.join(loaderSystemFolder, loaderJsonData[libraryNode]["library_path"]) + + if not os.path.exists(librarySystemPath): + print(">>> could not find loader library " + librarySystemPath) + return + + print(">>> modifiying and writing loader json " + loaderName) + loaderBundleFile = open(loaderBundlePath, 'w') + loaderLibraryName = os.path.basename(librarySystemPath) + loaderJsonData[libraryNode]["library_path"] = os.path.join(libraryRelativeFolder, loaderLibraryName) + json.dump(loaderJsonData, loaderBundleFile, indent=4) + + print(">>> copying loader library " + loaderLibraryName) + frameworkBundleFolder = os.path.join(loaderBundleFolder, libraryRelativeFolder) + if not os.path.exists(frameworkBundleFolder): + os.makedirs(frameworkBundleFolder) + shutil.copy(librarySystemPath, os.path.join(frameworkBundleFolder, loaderLibraryName)) + 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]) +def process(binary): + binary = os.path.abspath(binary) if not os.path.exists(lib_path(binary)): os.makedirs(lib_path(binary)) print(">> gathering all linked libraries") @@ -177,5 +259,10 @@ def main(): print(">> copying and processing swift libraries") process_swift_libraries(binary) + print(">> copying and processing vulkan loader") + process_vulkan_loader(binary, "MoltenVK_icd.json", "vulkan/icd.d", "ICD") + if check_vulkan_max_version("1.3.261.1"): + process_vulkan_loader(binary, "VkLayer_khronos_synchronization2.json", "vulkan/explicit_layer.d", "layer") + if __name__ == "__main__": - main() + process(sys.argv[1]) |