【发布时间】:2012-09-13 08:39:58
【问题描述】:
我想使用install_name_tool 更改可执行文件的rpath,但我现在不知道rpath 是什么。 install_name_tool 要求在命令行中同时提供旧的和新的 rpath。在 macOS 下我可以使用什么命令来打印可执行文件的 rpath?
【问题讨论】:
标签: macos command-line terminal dynamic-linking darwin
我想使用install_name_tool 更改可执行文件的rpath,但我现在不知道rpath 是什么。 install_name_tool 要求在命令行中同时提供旧的和新的 rpath。在 macOS 下我可以使用什么命令来打印可执行文件的 rpath?
【问题讨论】:
标签: macos command-line terminal dynamic-linking darwin
首先,了解可执行文件不包含单个 rpath 条目,而是包含一个或多个条目的数组。
其次,您可以使用otool 列出图像的rpath 条目。使用otool -l,您将获得如下输出,其最后是rpath 条目:
Load command 34
cmd LC_LOAD_DYLIB
cmdsize 88
name /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (offset 24)
time stamp 2 Wed Dec 31 19:00:02 1969
current version 1038.32.0
compatibility version 45.0.0
Load command 35
cmd LC_RPATH
cmdsize 40
path @loader_path/../Frameworks (offset 12)
查找LC_RPATH 命令并记下path 条目下的路径。
编辑:关于 @loader_path 是什么:它是一种通用且动态的方式来引用想要加载框架的 Mach-O 对象。
虽然这是一个相当人为的例子,但我认为它应该明白这一点。假设我们有一个应用程序MyApp.app,它使用了一个框架MyFramework.framework。我们还会说,要正常运行,我需要将我的应用程序安装在 /Applications 中,而不是其他任何地方。因此,上述应用程序和框架的结构如下:
/Applications/MyApp.app/Contents/MacOS/MyApp(可执行)
/Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/MyFramework (Mach-O dylib)
如果我们要在可执行文件上运行 otool -L(注意大写 L),它将显示有关 MyFramework 的以下内容:
@rpath/MyFramework.framework/Versions/A/MyFramework
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
/usr/lib/libobjc.A.dylib
/usr/lib/libSystem.B.dylib
....
请注意,由于 MyFramework.framework 使用 @rpath 安装名称/路径,因此我们需要在运行时替换 @rpath 的运行时搜索路径条目。现在,我可以有一个 rpath 条目:
/Applications/MyApp.app/Contents/Frameworks
这会起作用,并且在运行时这两个部分会放在一起:
/Applications/MyApp.app/Contents/Frameworks + /MyFramework.framework/Versions/A/MyFramework ==
/Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/Versions/A/MyFramework
显然,硬编码这样的路径并不理想,因为简单地将应用程序移动到不同的文件夹或重命名应用程序本身会导致链接失败。
@loader_path 是一种简单的动态方式来引用应用程序的可执行文件,无论它可能存在于文件系统中的何处。在这种特殊情况下,在运行时它将使用正在运行的可执行文件的路径填充:/Applications/MyApp.app/Contents/MacOS/MyApp。然后我们可以说,要找到 MyFramework.framework,您只需上一个目录并转到 Frameworks。
【讨论】:
@loader_path 是什么?
@rpath,因为它们 consider it“更灵活和@executable_path 和@loader_path 的强大替代品。基本逻辑是,所有库都被链接并标识为@rpath/libname.dylib——没有具体路径。除了极少数例外,只要您的可执行文件的安装位置有LC_RPATH 条目,这就足够了。您不必摆弄安装后的库更新。
您可以使用otool -l myexecutable,但如果您只对rpaths 列表感兴趣,这会打印出很多不必要的信息。
您可以通过
过滤otool -l的输出到相关的rpath条目
otool -l myexecutable | grep RPATH -A2
【讨论】:
我发现我可以使用 macOS 打印共享库的安装名称
otool -D mylib
此外,我可以通过将-id 标志传递给install_name_tool 来直接设置安装名称,而无需参考旧的安装名称:
install_name_tool -id @rpath/my/path mylib
【讨论】:
我目前正在编写几个用于处理 DYLD 的脚本,这个回答了这个问题,所以我将其发布以供参考:
#!/usr/bin/env ruby
require 'open3'
stdout, stderr, status = Open3.capture3('/usr/bin/otool', '-l', *ARGV)
stdout.scan(/^ +cmd LC_RPATH$.*?^ +path (.*?) \(offset \d+\)$/m) {|(p)| puts p}
lsrpath /usr/local/microsoft/powershell/7/{pwsh,createdump,unknown.xyz}
@loader_path
'希望它有所帮助;-)
【讨论】:
我只是用otool命令
otool -l <my executable>
它打印出 rpath 字段。不需要任何长脚本。
【讨论】: