依赖于 boost 库的路径不完整

11

我的动态库已经成功构建,并依赖于使用自定义前缀(./b2 install --prefix=PREFIX)构建和安装的boost库。但是,当我在我的库上运行otool -L时,我会得到以下输出:

...
libboost_regex.dylib (compatibility version 0.0.0, current version 0.0.0)
libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
...

与其他依赖项不同,这个依赖项没有给出指向这些Boost库的完整路径。这导致我的库被应用程序加载时出现运行时错误。 我知道可以使用install_name_tool手动解决这个问题。但是我想弄清楚,为什么只有boost库会出现这种情况,而我的库依赖的其他依赖项却没有发生这种情况?

编辑

有人要求我举一个编译命令的例子,但像往常一样,“真实的例子”有点更加复杂。 在我的情况下,有一个依赖于Boost的库libA.dylib。然后,还有我的库libMy.dylib,它也依赖于libA.dylib和Boost。这个问题在configure步骤中出现,在此步骤中执行了简单的库存在检查(类似于AC_CHECK_LIB的自定义测试程序)。这个检查尝试构建一个小的测试程序,该程序链接到libA.dylib,以证明libA.dylib的可用性,但它失败了-由于找不到boost库的错误。当然,它找不到它们,因为otool -L libA.dylib给出了没有完整路径的boost库。


你能发布构建命令吗?如果没有在你的dll中指定-L以保留boost库路径,否则它可能只会查找LD路径。 - VladimirS
@user3545806,请查看上面的更新。 - peetonn
1个回答

5
为了回答问题:
“为什么只有Boost库会出现这种情况,而不会发生在我所依赖的其他库上?”
技术原因是Boost构建系统(bjam)明确将库的安装名称分配为仅文件名。它可能在内部使用编译器选项“-install_name”来实现此操作。
至于背后的原理,我不能代表Boost开发人员发言,所以我只能推测(这是一种糟糕的投资形式):在库中硬编码本地安装路径只会将“找不到库”运行时错误推迟到分发时间,因此他们可能希望您尽快正确地解决它。(或者这可能只是他们不想再投入更多时间来重新工作的旧行为;)

潜在解决方案

假设您的动态库(依赖于Boost)命名为myLib。正如您在问题中指出的那样,您可以非常好地更改记录在myLib中的Boost库的安装名称:
 install_name_tool myLib -change libboost_regex.dylib /full/path/to/libboost_regex.dylib

另一种方法是改变Boost库本身的安装名称:

install_name_tool libboost_regex.dylib -id $new_name

使用这种方法,在针对修改过的libboost_regex.dylib构建时,安装名称$new_name现在将被记录在myLib中。
你现在需要决定为$new_name赋予什么值。当然可以是库的完整路径,这样Boost库就会像其他依赖项一样运行。
另一种更易于分发的选择是使用RPath。(基于RPath的安装名称把查找依赖项的负担放在了依赖方身上:依赖方存储一组路径列表,将尝试用"@rpath"替换) :
install_name_tool libboost_regex.dylib -id @rpath/libboost_regex.dylib #assign a rpath dependant install name to a boost library
 install_name_tool myLib -add_rpath $a_rpath_prefix # adds a candidate to substitute @rpath with, stored in myLib

$a_rpath_prefix 可以是包含 Boost 库的文件夹路径,适用于开发环境。如果某一天您需要分发库,则可以嵌入相对路径的 Boost 依赖项(或在 OS X Bundle 中),并添加一个 RPath 值来跟随此相对路径。

问题编辑

针对您描述的无法定位 Boost 的自动检查特定情况,您可以尝试使用上述提出的替代解决方案来解决。它会更改存储在库本身中的 Boost 库的安装名称(因此将被复制到 libA.dylib 中):

install_name_tool libboost_regex.dylib -id /full/path/to/libboost_regex.dylib

在这种特定的用例中,甚至更简单的解决方案是将 DYLD_FALLBACK_LIBRARY_PATH 填充为包含 Boost 库的目录路径。动态链接器会在这些目录中查找库文件,因此它将在那里找到 boost 库。在运行构建检查的终端中:
export DYLD_FALLBACK_LIBRARY_PATH=/full/path/to/;$DYLD_FALLBACK_LIBRARY_PATH

感谢您的见解。当我想要分发时,我会在可执行文件和所有依赖库上运行install_name_tool。这个问题涉及开发阶段(请参见我上面问题的更新),并影响到想要配置开发环境并尝试构建我的项目的新开发人员。 - peetonn
@peetonn 感谢您的评论。我认为您可以使用编辑部分中的解决方案来修复任何开发环境。此外,如果这并没有回答您的问题,那么我可能误解了您的问题(在这种情况下,您能否请尝试重新表述一下?) - Ad N
嗯,我想这里真正的问题是如何为想要构建我的库/应用程序的第三方开发人员提供最“易于部署”的开发环境。最初,我试图解决问题的根源(即boost libs没有安装路径),但现在似乎我将不得不在构建libA.dylib之前提供额外的步骤,在构建boost后执行类似于“准备boost库”的步骤,用户将不得不像您描述的那样手动进行。我仍然不确定这是否是最佳解决方案,但我会将您的答案标记为可能的解决方案。谢谢! - peetonn
非常感谢。这是我迄今为止看到的最好的解释。我希望Boost开发人员能够阅读它。 - Slava

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