Skip to content

Commit

Permalink
Allow custom otool and install_name_tool programs
Browse files Browse the repository at this point in the history
  • Loading branch information
sfackler committed Jun 29, 2023
1 parent 470c8ee commit 6d67569
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 10 deletions.
21 changes: 12 additions & 9 deletions conan/tools/apple/apple.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ def libtool(self):
return self.find('libtool')


def _get_dylib_install_name(path_to_dylib):
command = "otool -D {}".format(path_to_dylib)
def _get_dylib_install_name(otool, path_to_dylib):
command = f"{otool} -D {path_to_dylib}"
output = iter(check_output_runner(command).splitlines())
# Note: if otool return multiple entries for different architectures
# assume they are the same and pick the first one.
Expand All @@ -194,26 +194,29 @@ def fix_apple_shared_install_name(conanfile):
*install_name_tool* utility available in macOS to set ``@rpath``.
"""

otool = conanfile.conf.get("tools.apple:otool_program", default="otool")
install_name_tool = conanfile.conf.get("tools.apple:install_name_tool_program", default="install_name_tool")

def _darwin_is_binary(file, binary_type):
if binary_type not in ("DYLIB", "EXECUTE") or os.path.islink(file) or os.path.isdir(file):
return False
check_file = f"otool -hv {file}"
check_file = f"{otool} -hv {file}"
return binary_type in check_output_runner(check_file)

def _darwin_collect_binaries(folder, binary_type):
return [os.path.join(folder, f) for f in os.listdir(folder) if _darwin_is_binary(os.path.join(folder, f), binary_type)]

def _fix_install_name(dylib_path, new_name):
command = f"install_name_tool {dylib_path} -id {new_name}"
command = f"{install_name_tool} {dylib_path} -id {new_name}"
conanfile.run(command)

def _fix_dep_name(dylib_path, old_name, new_name):
command = f"install_name_tool {dylib_path} -change {old_name} {new_name}"
command = f"{install_name_tool} {dylib_path} -change {old_name} {new_name}"
conanfile.run(command)

def _get_rpath_entries(binary_file):
entries = []
command = "otool -l {}".format(binary_file)
command = "{otool} -l {}".format(binary_file)
otool_output = check_output_runner(command).splitlines()
for count, text in enumerate(otool_output):
pass
Expand All @@ -223,7 +226,7 @@ def _get_rpath_entries(binary_file):
return entries

def _get_shared_dependencies(binary_file):
command = "otool -L {}".format(binary_file)
command = f"{otool} -L {binary_file}"
all_shared = check_output_runner(command).strip().split(":")[1].strip()
ret = [s.split("(")[0].strip() for s in all_shared.splitlines()]
return ret
Expand All @@ -239,7 +242,7 @@ def _fix_dylib_files(conanfile):
shared_libs = _darwin_collect_binaries(full_folder, "DYLIB")
# fix LC_ID_DYLIB in first pass
for shared_lib in shared_libs:
install_name = _get_dylib_install_name(shared_lib)
install_name = _get_dylib_install_name(otool, shared_lib)
#TODO: we probably only want to fix the install the name if
# it starts with `/`.
rpath_name = f"@rpath/{os.path.basename(install_name)}"
Expand Down Expand Up @@ -282,7 +285,7 @@ def _fix_executables(conanfile, substitutions):
existing_rpaths = _get_rpath_entries(executable)
rpaths_to_add = list(set(rel_paths) - set(existing_rpaths))
for entry in rpaths_to_add:
command = f"install_name_tool {executable} -add_rpath {entry}"
command = f"{install_name_tool} {executable} -add_rpath {entry}"
conanfile.run(command)

if is_apple_os(conanfile):
Expand Down
2 changes: 2 additions & 0 deletions conans/model/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
# Tools
"tools.android:ndk_path": "Argument for the CMAKE_ANDROID_NDK",
"tools.android:cmake_legacy_toolchain": "Define to explicitly pass ANDROID_USE_LEGACY_TOOLCHAIN_FILE in CMake toolchain",
"tools.apple:otool_program": "Path to otool executable",
"tools.apple:install_name_tool_program": "Path to install_name_tool executable",
"tools.build:skip_test": "Do not execute CMake.test() and Meson.test() when enabled",
"tools.build:download_source": "Force download of sources for every package",
"tools.build:jobs": "Default compile jobs number -jX Ninja, Make, /MP VS (default: max CPUs)",
Expand Down
2 changes: 1 addition & 1 deletion conans/test/unittests/tools/apple/test_apple_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,5 @@ def test_get_dylib_install_name():
for mock_output in (single_arch, universal_binary):
with mock.patch("conan.tools.apple.apple.check_output_runner") as mock_output_runner:
mock_output_runner.return_value = mock_output
install_name = _get_dylib_install_name("/path/to/libwebp.7.dylib")
install_name = _get_dylib_install_name("otool", "/path/to/libwebp.7.dylib")
assert "/absolute/path/lib/libwebp.7.dylib" == install_name

0 comments on commit 6d67569

Please sign in to comment.