RPATH无法扩展。

3

我在OS X上构建了一个可执行文件(名为demux),但它总是加载失败,我无法找到原因:

$ ./demux
RPATH failed to expanding     @rpath/sfeMovie.framework/Versions/2.0/sfeMovie to: @executable_path/sfeMovie.framework/Versions/2.0/sfeMovie
dyld: Library not loaded: @rpath/sfeMovie.framework/Versions/2.0/sfeMovie
  Referenced from: …current_dir/./demux

这个框架与可执行文件并列。Otool 显示如下:

$ otool -L sfeMovie.framework/Versions/2.0/sfeMovie 
sfeMovie.framework/Versions/2.0/sfeMovie:
@rpath/sfeMovie.framework/Versions/2.0/sfeMovie (compatibility version 2.0.0, current version 2.0.0)

并且:

$ otool -L demux 
demux:
@rpath/sfeMovie.framework/Versions/2.0/sfeMovie (compatibility version 2.0.0, current version 2.0.0)

鉴于此,我认为将 @executable_path 添加到可执行文件的运行时搜索路径中,可以使它查找任何框架和库,其相对安装名称仅以 @rpath 为前缀(例如 @rpath/sfeMovie.framework/…),并且这些框架和库紧邻于可执行文件。为了确保运行时搜索路径正确:
$ otool -l demux | grep LC_RPATH -A 2
      cmd LC_RPATH
  cmdsize 32
     path @executable_path (offset 12)

但是这个方法失败了,我不知道为什么。对我来说,@executable_path/sfeMovie.framework/Versions/2.0/sfeMovie 看起来是正确的路径,但它仍然失败了... 是否有误用 @rpath 或 @executable_path 的情况?
2个回答

4

我可以用一个快速测试项目复现你的问题。当我在 LD_RUNPATH_SEARCH_PATH 构建设置末尾添加了一个斜杠时,问题得到了解决。

不要这样写:

@executable_path

你应该尝试一下

@executable_path/
< p >现在从otool -l的输出看起来像这样:

      cmd LC_RPATH
  cmdsize 32
     path @executable_path/ (offset 12)

通常情况下,您可以使用我的dyld分析脚本检查您的顶级可执行文件(在本例中为“demux”),该脚本位于https://github.com/liyanage/macosx-shell-scripts/blob/master/checklibs.py

./checklibs.py demux

这个工具试图忠实地复制dyld的解析逻辑。它通常可以提供有关哪些引用不起作用的提示,但在这种情况下,它无法捕捉到缺少尾部斜杠的问题。我将相应地更新它以匹配dyld的行为。

哦,就是这样!!非常感谢!!它更像是一个dyld错误,因为它打印出了一个有效的扩展路径但无法加载...不管怎样,问题已解决 :) 我也会看一下你的脚本 :) - Ceylo
很高兴听到它可以正常工作。我同意,这种行为与文档不符。 - Marc Liyanage
1
看起来 @executable_path(不带“/”)在10.9 El Capitan上运行良好,尽管我可以确认在10.7 Mavericks上你必须使用 @exectuable_path/(我有一个编译到10.7目标的应用程序,在10.9上工作但在10.7上不工作 - 在花费了几个小时找问题后,我发现“/”是问题所在...)感谢 @marc-liyanage! - pawel

0

demux 包含一个 @rpath 链接,而 RPATH 包含 @executable_path,但是 dyld man page 中说,“你甚至可以添加一个以 @loader_path 开头的 LC_RPATH 加载命令路径”,这似乎意味着 @executable_path 在 RPATH 中不被允许。

如果 demux 直接包含 @executable_path 而不是间接引用到 RPATH,那么它将起作用。

有关详细信息,请参见 man dylddyld.cpp

如果这是 demux.c

#include <stdio.h>

int foo();

int main() {
    printf("%d\n", foo());
}

这是 lib/sfeMovie.c

int foo() {
    return 42;
}

这是你的Makefile

run:
        $(MAKE) clean
        $(MAKE) demux
        cd .. && "$(shell pwd -P)/demux"

demux: demux.o lib/sfeMovie.dylib
        cc -o $@ $^
        install_name_tool \
            -change \
                'lib/sfeMovie.dylib' \
                 '@executable_path/lib/sfeMovie.dylib' \
            $@

lib/sfeMovie.dylib: lib/sfeMovie.o
        cc -shared -o $@ $<

clean::
        rm -f demux *.o lib/*.o lib/*.dylib

然后 demux 正确加载库,即使当前目录不是包含 demux 的目录。但是,如果sfeMovie引用了一堆其他库,则仍然可能需要RPATH。

使用您的方案,用户被强制将库放置在可执行文件旁边的lib目录中。如果他不想这样做,他将不得不在链接之前编辑dylib(或在每个链接步骤后编辑可执行文件)。我忘记了关于这一点的一个细节:我想让用户选择放置框架的位置,这就是为什么我正在尝试使用rpath的原因。谢谢 :) - Ceylo

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