linux - ld : Using -rpath, $ORIGIN 在共享库中(递归)

标签 linux linker shared rpath

我刚刚做了一个使用 ld 的 -rpath 的基本示例带有 $ORIGIN 的选项here (有关工作版本,请参阅第二个响应)。我正在尝试创建一个示例,其中 main.run链接到 foo.so ,它又链接到 bar.so , 全部使用 rpath$ORIGIN .

运行时文件结构是:

  • project/
    • lib/
      • dir/
        • sub/
          • bar.so
        • foo.so
    • run/
      • main.run (failing to build)

我正在构建 foo.so 使用:

g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/dir/foo.so obj/foo.o -Wl,-soname,foo.so -Wl,-rpath,'$ORIGIN/sub' -Llib/dir/sub -l:bar.so

构建良好。 ldd lib/dir/foo.so甚至可以找到 bar.so .

但是,当我尝试链接 main.run 时至 foo.so , foo.so找不到 bar.so。

我正在构建 main.so 使用:

g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Llib/dir -l:foo.so

如果 foo.so 的另一个版本,这工作正常使用不递归链接。 (在下面的项目中取消注释 make.sh 中的行以进行测试)。

但是,使用正常的 foo.so构建 main.run 时出现此错误:

/usr/bin/ld: warning: bar.so, needed by lib/dir/foo.so, not found (try using -rpath or -rpath-link)

所以我的问题是:

  1. 是否$ORIGIN在 foo.so 中解析为 project/lib/dir (其中 foo.so 是)或 project/run (main.run(链接它的可执行文件)在哪里)?
    ldd 似乎表明它是 project/lib/dir ,这似乎是最好的方法(尽管我尝试假设两者都假设)。
  2. 如何让这些链接(同时保留可重定位性)- 最好不使用 -rpath-link .

您可以下载项目here .这很简单,我可以做到。 4 个短资源和一个脚本。
解压后,运行./make.sh来自内部 project/ .

注意:我正在使用 -l: .这不应该改变任何东西,除了库被命名为 foo.so而不是 libfoo.so , 和 lunk -l:foo.so而不是 -lfoo .

最佳答案

嗯,我有一些工作。但我真的不明白为什么会这样。这对我来说就像是 ld 中的错误。

我为 main.run 编译运行了 strace -f -o/var/tmp/strace.out -- g++ ...。静态链接器实际上试图打开字面名称类似于“$ORIGIN/lib/dir/sub/bar.so”的文件,以及其他 20-30 个文件。 (换句话说,它正在寻找名为 $ORIGIN 的实际目录。说真的。)

它似乎还在 -rpath-link 路径中搜索名称“lib/dir/sub/bar.so”,而不仅仅是“bar.so”。我不知道为什么。

无论如何,这是为我工作的 main.run 的链接:

g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Wl,-rpath-link,. -Llib/dir -l:foo.so

它与您的相同,但插入了 -Wl,-rpath-link,.

[附录]

好的,我想我知道发生了什么。首先,静态链接器 (GNU ld) 根本不支持它链接的库中的 $ORIGIN。

其次,使用 -lbar-l:bar.so 时的行为非常不同。

foo.so 上运行 readelf -a。在您的构建中,它显示了对“lib/dir/sub/bar.so”的依赖。这就是将 rpath-link 设置为“.”的原因。修复 main.run 的构建;它会导致静态链接器搜索“。”对于它找到的“lib/dir/sub/bar.so”。

如果将 bar.so 重命名为 libbar.so,并链接 foo.so 以使用 -lbar 而不是 -l:bar.so,则相同的 readelf 显示foo.so 现在依赖于“libbar.so”(没有路径组件)。使用 foo.so,您可以使用 -Wl,-rpath-link,lib/dir/sub 使 main.run 链接正常工作,如果您知道静态链接器只是不尊重 $ORIGIN。

顺便说一下,我没有在 GNU ld 手册中的任何地方看到 -l:bar.so 语法。出于好奇,你是怎么想出来的?

假设它是受支持的功能,这看起来有点像错误(-l:bar.so 创建对 lib/dir/sub/bar.so 的依赖,而不仅仅是 bar.so)。您可以通过将 rpath-link 设置为“.”来处理此错误。对于 main.run,或者您可以按照通常的方式重命名内容 (libxxx.so)。

关于linux - ld : Using -rpath, $ORIGIN 在共享库中(递归),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6323603/

相关文章:

linux - 如何列出包含特定字符串的文件名

linux - PointGrey SDK 在 StartCapture 上挂起

c - Arm Renesas 工具链链接器错误

c++ - 调用一个库函数,修改它的一些行为

linux - 如何制作完美的死符号链接(symbolic link)

regex - sed 问题 - 从文件中提取特定单词

c++ - 如果两个静态库使用相同的另一个静态库,如何避免 "LNK2005 Already Defined error"?

c++ - 模块 ilink32.dll 中的访问冲突

c# - 安装COM Add In后,在Excel中测试连接,出现蓝屏

c - 如何在任务/线程之间共享数据而不耦合它们?