我需要构建两个第三方共享库,因此其他项目将重用其.so文件。但是,在构建之后,这些库中的一个包含到另一个库的硬编码路径。此路径在其他计算机上无效并导致链接器警告。如何防止将完整路径嵌入到生成的.so文件中?
详细说明:
第一个图书馆来源:~/dev/A
第二个图书馆来源:~/dev/B
他们都有configure
脚本来生成make文件。图书馆B
取决于A
。所以,首先我构建A
:
$ ~/dev/A/configure --prefix=~/dev/A-install
$ make && make install
然后我建立B
:
$ ~/dev/B/configure --prefix=~/dev/B-install --with-A=~/dev/A-install
$ make && make install
然后我想将~/dev/A-install
和~/dev/B-install
的内容上传到我们的文件服务器,以便其他团队和构建机器可以使用二进制文件。但是当他们尝试使用B
时,他们会收到链接器警告:
/usr/bin/ld: warning: libA.so.2, needed by /.../deps/B/lib/libB.so, not found (try using -rpath or -rpath-link)
当我运行ldd libB.so
时,它会给出:
...
libA.so.2 => /home/alex/dev/A-install/lib/libA.so.2
显然这条路径只存在于我的机器上,在其他机器上找不到。
如何从libB.so
删除完整的硬编码路径?
感谢。
答案 0 :(得分:4)
对于两个软件包,您必须使用在运行时环境中有效的--prefix
值!
在安装时,覆盖prefix
或DESTDIR
(prefix
替换前缀,DESTDIR
前置,但工作更可靠)。 。像:
~/dev/A$ ./configure
~/dev/A$ make
~/dev/A$ make install prefix=~/dev/A-install
~/dev/B$ ./configure --with-A=~/dev/A-install
~/dev/B$ make
~/dev/B$ make install prefix=~/dev/B-install
或(这是首选,所有包构建工具都使用它):
~/dev/A$ ./configure
~/dev/A$ make
~/dev/A$ make install DESTDIR=~/dev/A-install
~/dev/B$ ./configure --with-A=~/dev/A-install/usr/local
~/dev/B$ make
~/dev/B$ make install prefix=~/dev/B-install
因为这种方式安装到~/dev/A-install/$prefix
,所以使用默认前缀~/dev/A-install/usr/local
。后一个选项的优点是,如果您重新定义某些特定的安装路径而不引用前缀(例如--sysconfdir=/etc
),DESTDIR
仍然会被添加到前面,而它不会受{ {1}}。
答案 1 :(得分:2)
-Wl,-rpath,~/deps/A/lib:~/deps/B/lib:~/dev/MyApp/bin
此链接器选项负责保存库中的路径。你需要以某种方式删除它。
请参阅./configure --help
是否有可能影响此选项的选项。另一种选择是手动编辑makefile并删除此选项。
== edit2 == 还有一件事
-L~/deps/A/lib -L~/deps/B/lib ~/deps/A/lib/libA.so ~/deps/B/lib/libB.so
如果libA.so和libB.so没有SONAME
,将它们链接为“〜/ deps / A / lib / libA.so”也会导致保存路径。在构建共享库时,使用-Wl,-soname,<soname>
链接器选项设置Soname。
如果在共享库中设置了soname,则使用“~/deps/A/lib/libA.so
”表单链接它是正常的。
与评论中提到的Jan一样,更好的方法是在没有-Llibrary/path -llibrary_name
的情况下使用“rpath
”。
-L~/deps/A/lib -L~/deps/B/lib -lA -lB
答案 2 :(得分:1)
当我运行ldd libB.so时,它会给出:
libA.so.2 =&gt; /home/alex/dev/A-install/lib/libA.so.2
此问题的低级解决方案是在链接libA.so库时使用选项“-soname = libA.so”。通过为共享对象定义SONAME,链接器在链接该共享对象时不会嵌入绝对路径。
OP正在使用“configure”,因此这不是一个简单的实现方案,除非他愿意进入configure脚本生成的Makefile的内容。
答案 3 :(得分:0)
我只是觉得我有同样的问题。 上述答案都没有帮助我。 每当我尝试
ldd libB.so
我会进入输出:
libA.so.1 => /home/me/localpath/lib/libA.so.1.0
因此我认为我有一条硬编码路径。事实证明我忘了我已经为本地测试设置了LD_LIBRARY_PATH。清除LD_LIBRARY_PATH意味着ldd在/ usr / lib /
中找到了正确的已安装库答案 4 :(得分:0)
除了操作系统配置中的列表之外,共享库和可执行文件还具有用于查找共享库的目录列表。 RPATH用于添加在运行时使用的共享库搜索路径。
如果要在RPATH中使用相对路径,则大多数Linux / UNIX(而不是AIX)系统支持一种特殊的语法-$ORIGIN
或${ORIGIN}
。
$ORIGIN
将在运行时扩展到二进制文件所在的目录-库或可执行文件。
因此,如果将可执行二进制文件放在prefix / bin /中,并将共享库放在prefix/lib/
中,则可以将条目添加到${ORIGIN}/../lib
之类的RPATH中,并将在运行时扩展到prefix/bin/../lib/
>
在Makefile中获取正确的语法通常是一个小技巧,因为您必须转义ORIGIN中的$
,以使其无法扩展。通常在Makefile中执行此操作:
g++ -Wl,-rpath=\$${ORIGIN}/../lib
Make和Shell都希望在您的环境中查找名为ORIGIN
的变量-因此需要对其进行两次转义。
答案 5 :(得分:-1)
使用 ld 的-rpath
和-soname
选项可能有所帮助(假设最近的Linux系统上ld
的binutils或binutils.gold包) ?