我已成功构建了动态库,并依赖于boost库,这些库是使用自定义前缀(./b2 install --prefix=PREFIX
)构建和安装的。但是,当我在我的库上运行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库。当我的lib被应用程序加载时,这会导致运行时错误。
我知道可以使用install_name_tool
手动修复此问题。但是,我试图弄明白,为什么它只发生在boost库中,并且不会发生在我的lib依赖的其他依赖项上?
修改
我被要求提供一个构建命令的例子,但是和往常一样,"现实生活"例子有点复杂。
就我而言,有一个库libA.dylib
依赖于boost。然后,我的图书馆libMy.dylib
取决于libA.dylib
并提升。在configure
步骤期间出现问题,此时执行简单的库存在检查(类似于AC_CHECK_LIB
的自定义测试程序)。此检查尝试构建一个与libA.dylib
链接的小测试程序,以证明libA.dylib
的可用性并且失败 - 由于无法找到增强库的错误。当然它找不到它们,因为otool -L libA.dylib
给了我没有完整路径的升级库。
答案 0 :(得分:5)
回答这个问题:
“为什么它只发生在boost库中,而且不会发生在我的lib所依赖的其他依赖项上?”
技术原因是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
使用此方法,当您根据修改后的$new_name
myLib
时,它现在将记录在libboost_regex.dylib
中
您知道必须决定给$ 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
在这个特定用例中,一个更简单的解决方案可能是使用包含Boost库的目录的路径填充DYLD_FALLBACK_LIBRARY_PATH
。动态链接器将在这些目录中查找库,因此它将在那里找到boost库。在将运行构建检查的终端中:
export DYLD_FALLBACK_LIBRARY_PATH=/full/path/to/;$DYLD_FALLBACK_LIBRARY_PATH