![如何使用相对路径链接到共享库?](https://linux22.com/image/141472/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E7%9B%B8%E5%AF%B9%E8%B7%AF%E5%BE%84%E9%93%BE%E6%8E%A5%E5%88%B0%E5%85%B1%E4%BA%AB%E5%BA%93%EF%BC%9F.png)
在里面ld.so(8) 的手册页,它说
在解析库依赖项时,动态链接器首先检查每个依赖项字符串以查看其是否包含斜杠(如果在链接时指定了包含斜杠的库路径名,则会发生这种情况)。 如果发现斜杠,则依赖项字符串将被解释为(相对或绝对)路径名,并使用该路径名加载库。
如何gcc
链接带有斜杠路径的库?我已经尝试过,-l
但这似乎只适用于它用来搜索各种路径的库名称,而不适用于路径参数本身。
一个后续问题:当以这种方式链接到相对路径时,相对路径是什么(例如包含二进制文件的目录或运行时的工作目录)?
我在搜索时找到的所有链接指南都讨论了使用RPATH
、LD_LIBRARY_PATH
和RUNPATH
。RPATH
已被弃用,并且大多数讨论都不鼓励使用LD_LIBRARY_PATH
.RUNPATH
以 开头的路径$ORIGIN
允许链接到相对路径,但它有点脆弱,因为它可以被 覆盖LD_LIBRARY_PATH
。我想知道相对路径是否会更健壮(因为我找不到任何讨论此问题的内容,我猜不是,可能是因为该路径是相对于运行时目录的)。
答案1
如果我们(暂时)忽略gcc
问题的 或 链接部分,而是使用以下命令修改二进制文件patchelf
在Linux系统上
$ ldd hello
linux-vdso.so.1 => (0x00007ffd35584000)
libhello.so.1 => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f02e4f6f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f02e533c000)
$ patchelf --remove-needed libhello.so.1 hello
$ patchelf --add-needed ./libhello.so.1 hello
$ ldd hello
linux-vdso.so.1 => (0x00007ffdb74fc000)
./libhello.so.1 => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f2ad5c28000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2ad5ff5000)
我们现在有一个带有相对路径库的二进制文件,如果存在包含libhello.so.1
文件的合适目录
$ cd english/
$ ../hello
hello, world
$ cd ../lojban/
$ ../hello
coi rodo
我们发现该路径是相对于进程的工作目录的,这会带来各种各样的问题,特别是安全 问题。这可能有一些富有成效的用途,也许可以测试库的不同版本。编译两个不同的二进制文件可能会更简单,或者patchelf
在必要的库中编译,而无需相对工作目录的复杂化。
编译步骤
libhello
只有一个helloworld
电话
$ cat libhello.c
#include <stdio.h>
void helloworld(void)
{
printf("coi rodo\n");
}
并通过编译
CFLAGS="-fPIC" make libhello.o
gcc -shared -fPIC -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
ln -s libhello.so.1.0.0 libhello.so.1
ln -s libhello.so.1.0.0 libhello.so
hello
进行调用的方法是helloworld
通过编译的
$ cat hello.c
int main(void)
{
helloworld();
return 0;
}
$ CFLAGS="-lhello -L`pwd`/english" make hello
没有补丁
事后看来,修改gcc
命令以使用相对目录路径:
$ gcc -shared -fPIC -Wl,-soname,./libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
$ cd ..
$ rm hello
$ CFLAGS="-lhello -L`pwd`/lojban" make hello
$ ldd hello | grep hello
./libhello.so.1 => not found
$ english
$ ../hello
hello, world
以正常方式编译库,然后根据需要使用patchelf
.
答案2
您可以通过将选项传递给链接器来完成此操作。例如,要从 ncurses 的构建目录(依赖于未安装的库)运行测试程序,我使用如下选项(在 gcc 命令行中):
-Wl,-rpath,../lib
它嵌入了一个相对路径名。相同的选项可以嵌入绝对路径名:
-Wl,-rpath,../lib:/usr/local/ncurses6/lib
这样做对于本地测试很有用,但由于多种原因不适用于在系统上安装。 Debian 有一项反对它的政策,可以追溯到 20 世纪 90 年代,尽管连贯的讨论很少(参见例如RPATH问题它收集了一些信息)。
答案3
如果使用gcc简单编译的话,只需要这样做:
gcc -o prog main.c ./liblib.so
编译后,程序的行为与 thrig 的答案相同。我认为这个命令应该只在测试环境中使用。