From ed99433277a1569ddeae8c8ef781f5d09ee42f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Fri, 17 Apr 2026 17:50:02 +0200 Subject: [PATCH] TOOLS/dylib_unhell.py: simplify the otool output processing There is no need to pipe things through shell and grep/awk, python is perfectly fine word processor. This makes it simpler to reason what is extracted and from where and also makes the script faster as we spawn only single process directly, not shell with multiple children. --- TOOLS/dylib_unhell.py | 61 ++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/TOOLS/dylib_unhell.py b/TOOLS/dylib_unhell.py index f2312e8f2e..8562d7a4fc 100755 --- a/TOOLS/dylib_unhell.py +++ b/TOOLS/dylib_unhell.py @@ -6,7 +6,6 @@ import re import shutil import subprocess import sys -from functools import partial sys_re = re.compile("^/System") usr_re = re.compile("^/usr/lib/") @@ -25,9 +24,16 @@ def is_user_lib(objfile, libname): "libswift" not in libname def otool(objfile, rapths): - command = f"otool -L '{objfile}' | grep -e '\t' | awk '{{ print $1 }}'" - output = subprocess.check_output(command, shell=True, universal_newlines=True) - libs = set(filter(partial(is_user_lib, objfile), output.split())) + output = subprocess.check_output( + ["otool", "-L", objfile], universal_newlines=True, + ) + libs = set() + for line in output.splitlines(): + if not line.startswith("\t"): + continue + lib = line.split()[0] + if is_user_lib(objfile, lib): + libs.add(lib) libs_resolved = set() libs_relative = set() @@ -39,41 +45,27 @@ def otool(objfile, rapths): return libs_resolved, libs_relative -def get_rapths(objfile): - rpaths: list[str] = [] - command = f"otool -l '{objfile}' | grep -A2 LC_RPATH | grep path" +def iter_rpaths(objfile): + output = subprocess.check_output( + ["otool", "-l", objfile], universal_newlines=True, + ) path_re = re.compile(r"^\s*path (.*) \(offset \d*\)$") + for line in output.splitlines(): + if match := path_re.match(line): + yield match.group(1).strip() - try: - result = subprocess.check_output(command, shell=True, universal_newlines=True) - except Exception: - return rpaths - - for line in result.splitlines(): - match = path_re.search(line) - if match is None: - continue - line_clean = match.group(1).strip() +def get_rapths(objfile): + loader_path = os.path.dirname(objfile) + return [ # resolve @loader_path - if line_clean.startswith("@loader_path/"): - line_clean = line_clean[len("@loader_path/"):] - line_clean = os.path.join(os.path.dirname(objfile), line_clean) - line_clean = os.path.normpath(line_clean) - rpaths.append(line_clean) - - return rpaths + os.path.normpath(rpath.replace("@loader_path", loader_path, 1)) + for rpath in iter_rpaths(objfile) + ] def get_rpaths_dev_tools(binary): - command = ( - f"otool -l '{binary}' | grep -A2 LC_RPATH | grep path | " - 'grep "Xcode\\|CommandLineTools"' - ) - result = subprocess.check_output(command, shell = True, universal_newlines=True) - path_re = re.compile(r"^\s*path (.*) \(offset \d*\)$") return [ - match.group(1).strip() - for line in result.splitlines() - if (match := path_re.search(line)) is not None + rpath for rpath in iter_rpaths(binary) + if "Xcode" in rpath or "CommandLineTools" in rpath ] def resolve_lib_path(objfile, lib, rapths): @@ -97,8 +89,7 @@ def resolve_lib_path(objfile, lib, rapths): def check_vulkan_max_version(version): try: subprocess.check_output( - f"pkg-config vulkan --max-version={version}", - shell=True, + ["pkg-config", "vulkan", f"--max-version={version}"], ) return True except Exception: