我想使用 更改可执行文件的rpathinstall_name_tool
,但我现在无法弄清楚rpath是什么。install_name_tool
需要在命令行上同时给出旧的和新的rpath。我可以使用什么命令在 macOS 下打印可执行文件的rpath ?
5 回答
首先,了解可执行文件不包含单个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
.
您可以使用otool -l myexecutable
,但如果您只对rpath的列表感兴趣,这会打印出很多不必要的信息。
您可以通过以下方式过滤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 字段。不需要任何长脚本。