install_name_tool 更新可执行文件以在 Mac OS X 中搜索 dylib

Posted

技术标签:

【中文标题】install_name_tool 更新可执行文件以在 Mac OS X 中搜索 dylib【英文标题】:install_name_tool to update a executable to search for dylib in Mac OS X 【发布时间】:2016-03-03 16:11:11 【问题描述】:

我有一个动态库 libtest.dylib,安装在 /PATH/lib 中,还有一个执行二进制文件 myapp,它使用安装在 /PATH/bin 中的 dylib。

我可以运行myapp来找到dylib,如下(Is it OK to use DYLD_LIBRARY_PATH on Mac OS X? And, what's the dynamic library search algorithm with it?):

DYLD_LIBRARY_PATH="/PATH/lib" myapp 

我想我可以使用install_name_tool 来更新库和可执行文件,以便可以使用 rpath 找到该库。我使用了这篇文章中的提示 - How can I specify the rpath in a dylib?。

在 lib 中,我执行了这个命令来添加 rpath。

install_name_tool -id "@rpath/libtest.dylib" libtest.dylib
install_name_tool -add_rpath "@executable_path/../lib/" libtest.dylib

在 bin 中,我执行了install_name_tool -add_rpath "@executable_path/../lib/" myapp

但是,当我在bin 目录中执行myapp 时,我收到了错误消息。

dyld: Library not loaded: libtest.dylib
  Referenced from: /PATH/bin/./myapp
  Reason: image not found
Trace/BPT trap: 5

otool -l myapp 显示 rpath 在 myapp 中已正确更新。

Load command 16
          cmd LC_RPATH
      cmdsize 40
         path @executable_path/../lib/ (offset 12)

libtest.dylib 也是如此

Load command 13
          cmd LC_RPATH
      cmdsize 40
         path @executable_path/../lib/ (offset 12)

可能出了什么问题?

添加

当然,我可以在编译和链接时使用cc -install_name,但我想知道如何在修改生成的dylib 和执行二进制文件时做同样的事情。

来自库:

cc -install_name "@loader_path/../lib/libtest.dylib" -dynamiclib -o libtest.dylib test.c

或者,install_name 可以使用@rpath:

cc -install_name "@rpath/libtest.dylib" -dynamiclib -o libtest.dylib test.c

从垃圾箱:

cc -I../lib -c main.c
cc -o main main.o ../lib/libtest.dylib -Wl,-rpath -Wl,@loader_path/../lib

或者只有一行:

cc -I../lib -L../lib -o main main.c -ltest -Wl,-rpath -Wl,@loader_path/../lib

【问题讨论】:

【参考方案1】:

来自otool -l,我分析了应该从原始库和二进制文件中添加或修改的内容。

Dylib

变化在 id:

Load command 2 <-- OLD
          cmd LC_ID_DYLIB
      cmdsize 40
         name libtest.dylib (offset 24)
   time stamp 1 Wed Dec 31 18:00:01 1969

Load command 2 <-- NEW
          cmd LC_ID_DYLIB
      cmdsize 64
         name @loader_path/../lib/libtest.dylib (offset 24)

这是完成更改的命令:

install_name_tool -id "@loader_path/../lib/libtest.dylib" libtest.dylib 

或者使用rpath:

install_name_tool -id "@rpath/libtest.dylib" libtest.dylib

可执行文件

有两个变化:rpath和load_dylib

Load command 12 <-- OLD
          cmd LC_LOAD_DYLIB
      cmdsize 40
         name libtest.dylib (offset 24)

Load command 12 <-- NEW
          cmd LC_LOAD_DYLIB
      cmdsize 64
         name @loader_path/../lib/libtest.dylib (offset 24)

这是完成更改的命令

install_name_tool -change libtest.dylib @loader_path/../lib/libtest.dylib myapp 

我还需要添加 rpath

Load command 14
          cmd LC_RPATH
      cmdsize 32
         path @loader_path/../lib (offset 12)

这是完成添加的命令:

 install_name_tool -add_rpath "@loader_path/../lib" myapp

想法

二进制文件试图找到库,它从install_name_tool -add_rpath "@loader_path/../lib" myapp 知道它的位置。它加载库,库的 id 是@rpath/libtest.dylib,其中@rpath 在可执行二进制文件中设置为@loader_path/../lib 以进行匹配。

参考

Can you please help me understand how Mach-O libraries work in Mac Os X?

Cmake

在使用 CMake 时,我们可以通过在 CMakeLists.txt 文件中添加以下内容来自动化该过程。

图书馆

应该加上id。

# https://cmake.org/pipermail/cmake/2006-October/011530.html
SET_TARGET_PROPERTIES (test
  PROPERTIES BUILD_WITH_INSTALL_RPATH 1
             INSTALL_NAME_DIR "@rpath"
  )
可执行文件

应该指定rpath:

SET(CMAKE_INSTALL_RPATH "@loader_path/../lib/libtest.dylib")

【讨论】:

似乎 dylib 中的属性在运行时并不重要。它们仅在构建时用于将属性从 dylib 复制到可执行文件。对于已经有一个链接到 dylib 的可执行文件但需要更改路径的情况,只需编辑可执行文件以设置 LC_LOAD_DYLIB 和可选的 LC_RPATH 就足够了。仅当第一个包含 @rpath 时才需要第二个。

以上是关于install_name_tool 更新可执行文件以在 Mac OS X 中搜索 dylib的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 install_name_tool:无法在 xcode 10.2 中打开文件

MACOS上install_name_tool有时无法改变rpath

install_name_tool 格式错误的对象(加载命令 23 cmdsize 为零) - Mac OS X Yosemite

“源文件比可执行文件更新”,但不是

在 NSBundle 中使用 ConnectionKit 框架

更改主 nib 文件基本名称、可执行文件名称和更新应用程序