【问题标题】:LD_LIBRARY_PATH does not workLD_LIBRARY_PATH 不起作用
【发布时间】:2017-02-17 00:12:38
【问题描述】:

我正在尝试编译一个使用 zlib 的演示,并且我认为我已经对 LD_LIBRARY_PATH 进行了正确设置,但它不适用于 -lz 标志,请您帮我找出问题所在吗?

lisanhu@lisanhu-XPS-15-9550:kseq$ echo $LD_LIBRARY_PATH 
/home/lisanhu/mine/repos/zlib/output/lib
lisanhu@lisanhu-XPS-15-9550:kseq$ make
gcc -g -O2 kseq_test.c -o kseq_test -lz
/usr/bin/ld: cannot find -lz
collect2: error: ld returned 1 exit status
Makefile:3: recipe for target 'all' failed
make: *** [all] Error 1
lisanhu@lisanhu-XPS-15-9550:kseq$ gcc -static -o kseq_test kseq_test.o -lz -L/home/lisanhu/mine/repos/zlib/output/lib
lisanhu@lisanhu-XPS-15-9550:kseq$

问题是,如果我使用-L 强制搜索文件夹,它可以工作,如果我将该文件夹放在 LD_LIBRARY_PATH 中,它就不起作用。我很确定我已经使用了export LD_LIBRARY_PATH,但它仍然不起作用。

这很烦人,因为如果我需要编译别人需要它的代码,设置环境变量来搜索库会更容易。

-------------更新------------

在另一台服务器上我试过了,它运行顺利

[lisanhu@farber tmp]$ export LD_LIBRARY_PATH=/home/1677/mine/repos/zlib/zlib-1.2.8
[lisanhu@farber tmp]$ ls
gmon.out  kseq.h  kseq.tar  kseq_test  kseq_test.c  Makefile
[lisanhu@farber tmp]$ make
cc -g -O2 kseq_test.c -o kseq_test -lz
[lisanhu@farber tmp]$ ldd kseq_test
    linux-vdso.so.1 =>  (0x00007fffb01a6000)
    libz.so.1 => /home/1677/mine/repos/zlib/zlib-1.2.8/libz.so.1 (0x00007f9556c83000)
    libc.so.6 => /lib64/libc.so.6 (0x00000031fa400000)
    /lib64/ld-linux-x86-64.so.2 (0x00000031fa000000)
[lisanhu@farber tmp]$ 

所以我的配置可能是正确的?有任何想法吗? 我已经在装有 Ubuntu 16.04 和 Fedora 25 的笔记本电脑上尝试过它,并于 2017 年 2 月 16 日更新为稳定版。我只能说它不是新更新的服务器。我想知道最新的gcc是否有问题?

-------------更新------------

我可能知道导致问题的原因。错误消息是cannot find -lz。似乎将-lz 视为单个文件。我发现ld 的用法中有-l-z 标志,而它可能会将-lz 转换为类似的东西,发现我们没有两个标志的参数,然后将它们组合在一起单个文件参数? 不完全确定我的推论,但有人知道如何处理这种情况吗?

-------------更新------------

完整的 Makefile

all:kseq.h kseq_test.c
        $(CC) -g -O2 kseq_test.c -o kseq_test -lz

clean:
        rm -f *.o

-------------更新------------

第 3 部分可能不是一个有效的解释,因为在将 -v 附加到 cc 之后,我发现 -lz 已成功传递给链接器

【问题讨论】:

  • 请向我们展示 Makefile 的相关部分,典型的是调用链接器的那些行。

标签: c gcc linker zlib


【解决方案1】:

2020 年 9 月 5 日更新

终于弄清了问题所在,因此为关心的人更新此答案。

当你编译你的代码时,你告诉它使用-lfoo之类的标志搜索共享库,编译器将为LIBRARY_PATH中的每个文件夹添加-L标志,链接器ld将搜索默认位置以外的每个 -L 文件夹。如果链接器找不到文件libfoo.solibfoo.a,它将失败。

解决此问题的方法是将-L 添加到库文件夹的编译行中,但这通常意味着您需要更改您的 Makefile,这不是我认为的最佳做法。

另一种方法是将您的库文件夹放入LIBRARY_PATH,因为gcc 和大多数编译器会在传递给链接器之前自动将-L 标志添加到这些文件夹中,无论您是否使用静态或动态库,编译器只会检查LIBRARY_PATH。所以LD_LIBRARY_PATH在编译时是没用的。

LD_LIBRARY_PATH 将在您实际运行程序时被系统检查。这是允许系统上存在同一个库的多个版本的好方法。例如,一些旧代码可能需要 CUDA 9,而一些新代码可能需要 CUDA 11,LD_LIBRARY_PATH 在这种情况下很有用。

===

终于找到解决办法了。只是不要使用 LD_LIBRARY_PATH 而是使用 LIBRARY_PATH 。它工作正常且顺利。从GNU ld cannot find library which is there 获取想法 仍然不清楚是什么原因,但至少现在可以正常工作了。

lisanhu@lisanhu-XPS-15-9550:kseq$ export LD_LIBRARY_PATH=~/mine/repos/zlib/output/lib;
lisanhu@lisanhu-XPS-15-9550:kseq$ make
cc -g -O2 kseq_test.c -o kseq_test -lz
/usr/bin/ld: cannot find -lz
clang-3.9: error: linker command failed with exit code 1 (use -v to see invocation)
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
lisanhu@lisanhu-XPS-15-9550:kseq$ ls
kseq.h  kseq_test.c  kseq_test.o  Makefile  test.seq
lisanhu@lisanhu-XPS-15-9550:kseq$ export LIBRARY_PATH=~/mine/repos/zlib/output/lib;
lisanhu@lisanhu-XPS-15-9550:kseq$ make
cc -g -O2 kseq_test.c -o kseq_test -lz
lisanhu@lisanhu-XPS-15-9550:kseq$ ls
kseq.h  kseq_test  kseq_test.c  kseq_test.o  Makefile  test.seq
lisanhu@lisanhu-XPS-15-9550:kseq$ ldd kseq_test
    linux-vdso.so.1 =>  (0x00007fffcd135000)
    /lib/$LIB/liblsp.so => /lib/lib/x86_64-linux-gnu/liblsp.so (0x00007f5fe93cb000)
    libz.so.1 => /home/lisanhu/mine/repos/zlib/output/lib/libz.so.1 (0x00007f5fe91b1000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5fe8dca000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5fe8bc6000)
    /lib64/ld-linux-x86-64.so.2 (0x000056051fc0c000)
lisanhu@lisanhu-XPS-15-9550:kseq$ 

【讨论】:

    【解决方案2】:

    LD_LIBRARY_PATH 用于在运行时查找共享库。在您的情况下,您希望在编译时提供路径......默认情况下,这不是环境变量(除非您的 makefile 明确查看您的环境)。您需要在命令行中将其传递给编译器,例如:

    gcc -g -O2 kseq_test.c -o kseq_test -L /home/lisanhu/mine/repos/zlib/output/lib -lz
    

    【讨论】:

    • 感谢您的回答,而实际上该文件夹中同时存在 libz.so 和 libz.a。我相信无论它是在寻找共享库还是静态库,它都应该找到它。此外,我需要将 -lz 放在 -L 之前,因为它需要在加载库之前加载路径。那不是我的 Makefile,它来自库作者的网站,这就是为什么我希望有一个环境变量解决方案而不是使用 -L,因为我不想更改 Makefile。关于它还有什么想法吗?
    • @SanhuLi:在调用链接器时检查 Makefile 是否使用了LDFLAGS 等。然后,您可以在运行 make 之前设置此 env/var/。顺便说一句,kcraigie 完全正确,链接器不使用LD_LIBRARY_PATH 来搜索库。
    • @alk 谢谢你的帮助,虽然我不同意你的想法。第一部分显示调用 make 之前 LD_LIBRARY_PATH 的值。 LD_LIBRARY_PATH 的值已设置。遗憾的是 Makefile 没有使用 LDFLAGS。第二部分在运行 gcc4.9 的服务器上运行,至少它搜索了 LD_LIBRARY_PATH 并找到了库。请注意,Makefile 没有使用 -static 标志,并且在进行链接时,我相信它会首先搜索动态链接文件,这由 ldd 结果显示,它使用 LD_LIBRARY_PATH 中的 .so 文件。
    • 如果您能尝试一下代码和库,我将不胜感激。 zlib 来自zlib.net,下载链接为zlib.net/zlib-1.2.11.tar.gz。测试用例来自lh3lh3.users.sourceforge.net/kseq.shtml,下载路径为lh3lh3.users.sourceforge.net/download/kseq.tar.bz2
    • 服务器使用的是gcc4.4,不是gcc4.9
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    相关资源
    最近更新 更多