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

55

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

我可以按照以下方式运行myapp来查找dylib(在Mac OS X上使用DYLD_LIBRARY_PATH是否可以? 使用它的动态库搜索算法是什么?):

DYLD_LIBRARY_PATH="/PATH/lib" myapp 

我认为我可以使用install_name_tool来更新库和可执行文件,以便可以通过rpath找到库。 我使用了这篇文章中的提示-如何在dylib中指定rpath?

在库中,我执行了此命令以添加rpath。

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

在终端中,我执行了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 显示 myapp 的 rpath 已经正确更新。

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个回答

65

通过使用 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以进行匹配。

参考资料

CMake

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

Library

应该添加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")

7
在运行时,似乎动态库中的属性并不重要。它们只在构建期间使用,用于将属性从动态库复制到可执行文件中。如果您已经将可执行文件链接到一个动态库,但需要更改路径,则仅需编辑可执行文件即可设置LC_LOAD_DYLIB,并且可以选择性地设置LC_RPATH。只有当第一个LC_LOAD_DYLIB中包含@rpath时才需要第二个。 - v.shashenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接