这是一个有趣的话题,我将尝试解释。所以,在这个例子中,我安装了一个小库jansson来测试。我将继续配置它以安装在非标准目录中:
./configure --prefix=/home/ubuntu/mystuff
现在在执行make install
此警告后出现:
Libraries have been installed in:
/home/ubuntu/mystuff/lib
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
好的,我将继续尝试使用其中一个测试套件程序链接它:
$ gcc test_dump.c -ljansson
test_dump.c:8:21: fatal error: jansson.h: No such file or directory
为了让 C 知道它可以使用什么,它首先需要知道包含文件。幸运的是,这只需要在编译时发生。我们使用包含目录传递,-I
因此gcc
知道在哪里可以找到包含文件:
$ gcc test_dump.c -I/home/ubuntu/mystuff/include -ljansson
/usr/bin/ld: cannot find -ljansson
好的,现在回到链接问题。因此,让我们在链接时尝试LD_LIBRARY_PATH
:
$ LD_LIBRARY_PATH="/home/ubuntu/mystuff/lib" gcc test_dump.c -I/home/ubuntu/mystuff/include -ljansson
/usr/bin/ld: cannot find -ljansson
这不起作用,这背后的原因是 gcc 正在查看不同的目录,如运行所示:
gcc -print-search-dirs
告诉 gcc 使用我们想要的目录,-L
使用:
$ gcc test_dump.c -I/home/ubuntu/mystuff/include -L/home/ubuntu/mystuff/lib -ljansson
$
现在我们可以使用一个名为的程序ldd
来查看它链接的内容:
$ ldd a.out
linux-vdso.so.1 => (0x00007fc4c872d000)
libjansson.so.4 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc4c8366000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc4c872e000)
您会注意到它对我们想要的库显示“未找到”。现在尝试解决这个问题:
$ LD_RUN_PATH="/home/ubuntu/mystuff/lib" gcc test_dump.c -I/home/ubuntu/mystuff/include -L/home/ubuntu/mystuff/lib -ljansson
这是一种方法,使用LD_RUN_PATH
. 它不仅链接到库,还链接到库的完整路径。再次运行ldd
显示:
$ ldd a.out
linux-vdso.so.1 => (0x00007fff481d7000)
libjansson.so.4 => /home/ubuntu/mystuff/lib/libjansson.so.4 (0x00007fe86b0dd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe86ad18000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe86b2eb000)
现在,当我们在不LD_RUN_PATH
涉及的情况下尝试这个时,我们会得到:
$ ./a.out
./a.out: error while loading shared libraries: libjansson.so.4: cannot open shared object file: No such file or directory
为了解决这个问题,LD_LIBRARY_PATH
使用:
$ LD_LIBRARY_PATH="/home/ubuntu/mystuff/lib" ./a.out
$
然而,这有点像黑客和皱眉。大卫巴尔在这件事上写了一篇很棒的文章。发生的事情是有一个动态库加载器,ld.so/ld-linux.so
它“加载程序所需的共享库,准备程序运行,然后运行它”。如果您查看ld.so
联机帮助页,它会指出:
The necessary shared libraries needed by the program are searched for in the following order
o Using the environment variable LD_LIBRARY_PATH (LD_AOUT_LIBRARY_PATH for a.out programs). Except if the executable is a setuid/setgid binary, in which case it is ignored.
o From the cache file /etc/ld.so.cache which contains a compiled list of candidate libraries previously found in the augmented library path. Libraries installed in hardware capabilities
directories (see below) are prefered to other libraries.
o In the default path /lib, and then /usr/lib.
那/etc/ld.so.cache
就是您希望该路径所在的位置。此缓存是通过ldconfig
使用生成的/etc/ld.so.conf
。如果您在 Ubuntu 上查看该文件:
include /etc/ld.so.conf.d/*.conf
这就是它所说的一切。默认情况下,在/etc/ld.so.conf.d
目录中是 glib、gcc 的目录,/usr/local/lib
因为它在默认路径之外。要将我们想要的目录添加到缓存中,您只需在该目录中添加一个文件:
$ sudo vim /etc/ld.so.conf.d/50-jansson.conf
- add /home/ubuntu/mystuff/lib to the file -
$ sudo ldconfig
这将为/etc/ld.so.cache
加载程序重新生成该文件。ldconfig
您可以通过打印出缓存目录来确认该目录已被拾取:
$ ldconfig -p | grep "mystuff"
libjansson.so.4 (libc6,x86-64) => /home/ubuntu/mystuff/lib/libjansson.so.4
libjansson.so (libc6,x86-64) => /home/ubuntu/mystuff/lib/libjansson.so
现在,如果我们ldd
再次尝试运行:
$ ldd a.out
linux-vdso.so.1 => (0x00007fff1e510000)
libjansson.so.4 => /home/ubuntu/mystuff/lib/libjansson.so.4 (0x00007f529da67000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f529d6a8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f529dc7b000)
最后运行程序:
$ ./a.out
$
这一切都有效!这是在进行链接时查看后端发生的情况。有关更多详细信息,我建议查看man ld.so
and man ldconfig
。如果您需要任何澄清,请随时询问。