【问题标题】:How to use dylib in Mac OS X (C++)如何在 Mac OS X (C++) 中使用 dylib
【发布时间】:2011-06-08 07:15:32
【问题描述】:

我创建了一个应用程序(一个可执行文件),成功调用了一些 dylib。但是,dylib 文件和可执行文件位于不同的目录中。我将包含 dylib 文件的目录添加到 $PATH 环境变量中。但是,它仍然无法加载。我将所有dylib文件复制到可执行文件中,程序终于运行了。这确认 dylib 文件没有问题。但是,我怎样才能告诉操作系统找到它呢?
在 Windows 中,我只需要将包含 dll 文件的目录路径添加到 $PATH。对于 Mac OS X,我需要做什么?

【问题讨论】:

  • 使用otool -L app检查您的应用程序的依赖关系。如果它们被硬编码为绝对路径,则使用install_name_tool -change old new file 将它们修改为相对路径。之后,链接器可能会在您的 DYLD_LIBRARY_PATH 环境变量中找到一个库。

标签: c++ macos build load dylib


【解决方案1】:

阅读 Justin 提供的链接后,我成功地使用 @executable_path 令牌将我的 dylib install_name 更改为指向我的可执行文件所在的同一目录。

@executable_path 绝对路径很烦人。有时您希望将框架嵌入到应用程序中,而不必安装 将框架放入 /Library 或类似位置。

Mac 对此的解决方案是@executable_path。这是一个魔法令牌 当放置在库的安装名称的开头时,得到 扩展为加载它的可执行文件的路径,减去 最后一个组件。例如,假设 Bar.app 链接到 Foo.framework。如果 Bar.app 安装在 /Applications 中, @executable_path 将扩展为 /Applications/Bar.app/Contents/MacOS。 如果您打算在 Contents/Frameworks 中嵌入框架,那么您 可以将 Foo.framework 的安装名称设置为 @executable_path/../Frameworks/Foo.framework/Versions/A/Foo。这 动态链接器会将其扩展为 /Applications/Bar.app/Contents/MacOS/../Frameworks/Foo.framework/Versions/A/Foo 并会在那里找到框架。

http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html

我会用一个例子来演示。

假设我有以下可执行文件 /opt/local/bin/convert,它的 dylib 位于 /opt/local/lib 中。 我想将它复制到另一个目录,并让它从与我复制可执行文件的目录相同的目录中加载它的 dylib。

> mkdir ~/tmp/bin
> cp /opt/local/bin/convert ~/tmp/bin

获取可执行文件dylib的列表

> otool -L ~/tmp/bin/convert
~/tmp/bin/convert:
    /opt/local/lib/libtiff.3.dylib (compatibility version 13.0.0, current version 13.5.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
    /opt/local/lib/libjpeg.8.dylib (compatibility version 12.0.0, current version 12.0.0)
    /opt/local/lib/libfontconfig.1.dylib (compatibility version 6.0.0, current version 6.4.0)
    /opt/local/lib/libiconv.2.dylib (compatibility version 8.0.0, current version 8.1.0)
    /opt/local/lib/libfreetype.6.dylib (compatibility version 15.0.0, current version 15.0.0)
    /opt/local/lib/libexpat.1.dylib (compatibility version 7.0.0, current version 7.2.0)
    /opt/local/lib/libbz2.1.0.dylib (compatibility version 1.0.0, current version 1.0.6)
    /opt/local/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.6)
    ...

我只关心 /opt/local/lib 目录中的 dylib,所以我们只提取 /opt 中的 dylib。我想保持所有其他 dylib 引用完整,尤其是对 /usr/lib/libSystem 的东西。

> DYLIBS=`otool -L ~/tmp/bin/convert | grep "/opt" | awk -F' ' '{ print $1 }'`

将可执行文件引用的所有 dylib 复制到可执行文件已复制到的同一目录。

> for dylib in $DYLIBS; do cp $dylib ~/tmp/bin/; done;

使用install_name_tool 更改我们在上述步骤中提取的所有dylib 的安装名称,并通过在dylib 名称前添加@executable_path 来替换它们。这将使动态链接器在与可执行文件所在的目录相同的目录中查找 dylib。

> for dylib in $DYLIBS; do install_name_tool -change $dylib @executable_path/`basename $dylib` ~/tmp/bin/convert; done;

确认安装名称已更改,并且 libSystem 仍指向 /usr/lib/libSystem。

> otool -L ~/tmp/bin/convert
~/tmp/bin/convert:
    @executable_path/libtiff.3.dylib (compatibility version 13.0.0, current version 13.5.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
    @executable_path/libjpeg.8.dylib (compatibility version 12.0.0, current version 12.0.0)
    @executable_path/libfontconfig.1.dylib (compatibility version 6.0.0, current version 6.4.0)
    @executable_path/libiconv.2.dylib (compatibility version 8.0.0, current version 8.1.0)
    @executable_path/libfreetype.6.dylib (compatibility version 15.0.0, current version 15.0.0)
    @executable_path/libexpat.1.dylib (compatibility version 7.0.0, current version 7.2.0)
    @executable_path/libbz2.1.0.dylib (compatibility version 1.0.0, current version 1.0.6)
    @executable_path/libz.1.dylib (compatibility version 1.0.0, current version 1.2.6)
    ...

【讨论】:

  • 请注意,您似乎也必须为每个库文件执行此操作,因为它们还可能包含指向绝对路径的链接
  • 整个install_name_tool舞蹈必须是递归的,直到你到达仅依赖于系统库的“叶”库,即/usr/lib或/System/Library下的东西。
【解决方案2】:

您需要设置DYLD_LIBRARY_PATH 环境变量。

来自dyld man page:

      This  is  a  colon  separated  list  of directories that contain libraries. The dynamic linker
      searches these directories before it searches the default locations for libraries.  It  allows
      you to test new versions of existing libraries.

      For  each  library  that  a program uses, the dynamic linker looks for it in each directory in
      DYLD_LIBRARY_PATH in turn. If it still can't find the library,  it  then  searches  DYLD_FALL-
      BACK_FRAMEWORK_PATH and DYLD_FALLBACK_LIBRARY_PATH in turn.

【讨论】:

  • 谢谢!我也通过google找到了这个,我确实设置了DYLD_LIBRARY_PATH,但是它不起作用,问题仍然存在!我很困惑
  • 嗨,EmeryBerger,你的 DYLD_LIBRARY_PATH 变量原来是空的吗?我的是。一开始我不知道这是否是错误的。
  • 但是@Justin 的答案中的页面包含了一个更好的解决方案,即使用指向目录的 -rpath 编译代码(如果您可以选择的话)。
  • 我阅读了文档但无法理解,我尝试将 -rpath 添加到链接器标志,它不起作用,添加到编译器标志也不起作用......我只是想知道为什么 DYLD_LIBRARY_PATH 对我不起作用?我还需要设置什么吗?
  • @AlfredZhong 确保在设置 DYLD_LIBRARY_PATH 时使用 export。请参阅此处了解原因:stackoverflow.com/a/8699244/402807
【解决方案3】:

【讨论】:

    【解决方案4】:

    如果 dylib 位于库的 INSTALL_NAME 指定的位置,它将 Just Work*。

    否则,您可以将 dylib 的位置添加到 DYLD_LIBRARY_PATH。您可能想阅读dyld documentation。

    *) 完全准确地说,它需要位于 DYLD_ROOT_PATH/INSTALL_NAME,但很少使用 DYLD_ROOT_PATH。

    【讨论】:

    • 抱歉,“库的安装名称”是什么?我添加了DYLD_LIBRARY_PATH,它不起作用,很困惑。
    • 需要导出变量:export DYLD_LIBRARY_PATH=/usr/local/lib`
    猜你喜欢
    • 2015-12-01
    • 2011-04-01
    • 2011-08-15
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 2017-07-30
    • 1970-01-01
    相关资源
    最近更新 更多