usr/bin/ld: 找不到-l<库的名称>

645

我正在尝试编译我的程序,但返回了以下错误:

usr/bin/ld: cannot find -l<nameOfTheLibrary>
在我的 makefile 中,我使用了 g++ 命令,并链接到我的库,该库是指向另一个目录中的库的符号链接。
请问是否有任何选项可以添加,以使它能够正常工作?

1
需要更多信息。您发出了哪个命令来编译您的程序?您可以使用“make -n your-target”来让make仅打印它通常会调用的命令。 - djf
我的命令是这个:g++ -<选项> objetc1.o objetc2.o objetc3.o objetc4.o -L<库路径> -l<库名称> -lpthread -o myexe。 - ZoOo
4
您希望链接的库是否和您当前使用的架构(例如32/64位)相同?您希望链接的库是否是自定义库?库名称很重要,因为在使用“-l”开关时,它必须以“lib<name>”开头(例如,您已经链接的“libpthread.so”)。 - Ortwin Angermeier
1
问题出在我的符号链接库上,它不太好!感谢您的帮助! - ZoOo
由于您在下面提供的答案解决了您的问题,请接受该答案。 - goldenmean
显示剩余4条评论
14个回答

650
为了确定链接器正在寻找什么,请在详细模式下运行它。 例如,在尝试编译支持ZLIB的MySQL时,我遇到了这个问题。在编译期间,我收到了类似这样的错误:
/usr/bin/ld: cannot find -lzlib

我进行了一些谷歌搜索,并发现许多人都遇到了不同类型的相同问题,他们会建议确保 .so 文件实际上存在并且如果不存在,则创建指向版本化文件的符号链接,例如 zlib.so.1.2.8。但是,当我检查时,zlib.so 是存在的。因此,我想,这肯定不是问题所在。

我在互联网上找到了另一篇文章,建议使用 LD_DEBUG=all 运行 make:

LD_DEBUG=all make

虽然我获得了大量的调试输出,但它实际上并没有帮助。它只增加了更多的困惑。所以,我差点放弃。

然后,我有了顿悟。我想去查看ld命令的帮助文本:

ld --help

从那个过程中,我找到了如何在详细模式下运行ld(可以想象一下):

ld -lzlib --verbose

我得到的输出是:

==================================================
attempt to open /usr/x86_64-linux-gnu/lib64/libzlib.so failed
attempt to open /usr/x86_64-linux-gnu/lib64/libzlib.a failed
attempt to open /usr/local/lib64/libzlib.so failed
attempt to open /usr/local/lib64/libzlib.a failed
attempt to open /lib64/libzlib.so failed
attempt to open /lib64/libzlib.a failed
attempt to open /usr/lib64/libzlib.so failed
attempt to open /usr/lib64/libzlib.a failed
attempt to open /usr/x86_64-linux-gnu/lib/libzlib.so failed
attempt to open /usr/x86_64-linux-gnu/lib/libzlib.a failed
attempt to open /usr/local/lib/libzlib.so failed
attempt to open /usr/local/lib/libzlib.a failed
attempt to open /lib/libzlib.so failed
attempt to open /lib/libzlib.a failed
attempt to open /usr/lib/libzlib.so failed
attempt to open /usr/lib/libzlib.a failed
/usr/bin/ld.bfd.real: cannot find -lzlib

叮铃,叮铃,叮铃......

最终,为了可以使用我自己的ZLIB版本(而不是捆绑的版本)编译MySQL,我进行了如下修复:

sudo ln -s /usr/lib/libz.so.1.2.8 /usr/lib/libzlib.so

看这里!


84
谢谢,这很有帮助。对于那些使用gcc来编译和链接程序的人(而不是直接使用ld),你可以在gcc的命令行参数中添加“-Xlinker --verbose”来让它将这个选项传递给ld。 - user473305
7
这也帮助了我。原先我的Makefile只支持静态库,所以它用了"-Wl,-Bstatic"。这会限制搜索仅为.a文件。通过使用详细输出选项,这一点变得非常清晰。一旦我移除了"-Wl,-Bstatic",就可以搜索共享库文件了。 - micah94
2
我正在使用FreeBSD 10。新的LLVM Clang cc接受形式为“-Wl,--verbose”的参数,并将“--verbose”传递给链接器。 - Christian - Reinstate Monica C
9
这就是我所说的完美答案!非常感谢。这节省了很多时间。补充一点,以帮助像我这样的人。它还可以用于调试与路径有关的问题。请确保使用命令 ld -L<目录路径> -l<库名称> --verbose 检查路径。 - sbhatt
3
@EdwardBlack 点击这里查看答案。对于gcc而言,只需添加-Wl,--verbose即可将详细信息传递给链接器。 - chembrad
显示剩余18条评论

251

如果你的库名是libxyz.so,并且它位于路径上:

/home/user/myDir

然后将其链接到您的程序中:

g++ -L/home/user/myDir -lxyz myprog.cpp -o myprog

15
我的库不是动态库(.so),而是静态库(.a)。问题是否来自于此? - ZoOo
4
那通常不应该有问题,链接器可以使用任何一个。 - djf
8
另一种链接库的方式是直接指定库的完整路径和名称,例如:g++ ../path/mylib.a。 - Saurabh Bhola
4
是的,但它仍然不起作用。我的库是一个符号链接,我认为问题来自于这个,因为当我在另一个目录中使用库时它可以工作! - ZoOo
2
你的符号链接是否正确指向实际位置的库?你能发布一下对符号链接的“ll”命令的输出吗? - Saurabh Bhola
显示剩余6条评论

84

似乎没有任何答案解决了初学者常见的无法安装所需库的问题。

在Debianish平台上,如果缺少libfoo,你可以尝试使用以下命令安装:

apt-get install libfoo-dev

在开发工作中,即使是编译源代码以链接到库这样的微不足道的开发工作,也需要使用软件包的-dev版本。

软件包名称有时需要一些修饰(例如libfoo0-dev?没有lib前缀的foo-dev?等等),或者您可以使用发行版的软件包搜索来确定哪些软件包提供特定的文件。

(如果有多个软件包,则需要了解它们之间的区别。选择最酷或最流行的是常见的快捷方式,但对于任何严肃的开发工作都不是可接受的程序。)

对于其他架构(尤其是RPM),类似的程序适用,但细节会有所不同。


5
这正好帮我解决了一个在新服务器上使用Perl时遇到的问题。 apt-get install libperl-dev为我解决了这个问题。谢谢 :) - Andrew Newby
1
这样做!不需要对Makefile进行操作。 - Byron Whitlock
这可能是最常见的解决方案,帮助我在CentOS 7上编译cacti-spine。一个简单的yum install openssl-devel就解决了它。 - djluko
1
如果你发现符号链接以 .so 结尾的文件丢失了,但是你有一个类似于 libfoo.so.6 --> libfoo.so.6.0.2 的符号链接(例如),而不是手动创建符号链接,那么这是最好的解决方法。(意思是你已经安装了 libfoo 包,但没有安装 libfoo-dev) - dmaestro12
3
谢谢!我还想为初学者补充一点:1. apt install <package_name> != apt install <library_for_gcc_name>也就是说: 1. apt install sqlite3 != apt install libsqlite3-dev2. apt install dbus != apt install libdbus-1-dev libdbus-glib-1-dev你必须确保它是gcc的库! - John Huynh

78

编译时

当 g++ 报错 cannot find -l<nameOfTheLibrary> 时,意味着 g++ 在默认的共享库搜索路径(/usr/lib/usr/local/lib)里查找文件 lib{nameOfTheLibrary}.so,但是没有找到。

要解决这个问题,你可以将库文件 (lib{nameOfTheLibrary}.so) 提供到这些搜索路径中或者使用 -L 命令选项。 -L{path} 告诉 g++ (实际上是 ld) 在默认路径之外的路径 {path} 查找库文件。

示例:假设你在 /home/taylor/libswift.so 路径下有一个库文件,并且你想要将你的应用与该库链接起来。那么你应该向 g++ 提供以下选项:

g++ main.cpp -o main -L/home/taylor -lswift
  • Note 1: -l选项返回库名,但不包含其开头的lib和结尾的.so

  • Note 2: 在某些情况下,库文件名后跟其版本号,例如libswift.so.1.2。在这些情况下,g++也找不到库文件。解决此问题的简单方法是创建一个指向libswift.so.1.2的符号链接,称为libswift.so


运行时

当您将应用链接到共享库时,要求该库在运行应用程序时始终可用。在运行时,您的应用程序(实际上是动态链接器)在LD_LIBRARY_PATH中查找其库。它是一个存储路径列表的环境变量。

示例:在我们的libswift.so示例中,动态链接器无法在LD_LIBRARY_PATH中找到libswift.so(该变量指向默认搜索路径)。要解决此问题,您应该在该变量中追加包含libswift.so的路径。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/taylor

谢谢您的帖子!直到我将.so文件复制到/usr/lib之前,我一直忽略所有答案,但是我很感兴趣是否可以使用export来解决问题。尽管在make后的安装过程继续了更长时间,但出现了另一个错误。这次,找不到.so.0文件,但是.so.so.0文件都在我从源代码构建依赖包的目录中。您能帮忙解决吗? - A.Ametov
请注意,库名称也是大小写敏感的。我尝试链接OpenCl库,但没有成功,但是链接OpenCL库可以正常工作 :) - Alexey
@frogatto:真是一篇好文啊。我今天真的学到了很多东西。谢谢你。 - undefined

45

如果使用make通过g++进行编译时,可能不适合使用-L选项更改Makefile,则应定义LIBRARY_PATH。我将我的额外库放在了/opt/lib中,因此我执行了以下操作:

$ export LIBRARY_PATH=/opt/lib/

之后运行make进行编译和链接。

若要使用共享库定义运行程序:

$ export LD_LIBRARY_PATH=/opt/lib/

在执行程序之前。


24

首先,你需要了解 lxxx 的命名规则:

/usr/bin/ld: cannot find -lc
/usr/bin/ld: cannot find -lltdl
/usr/bin/ld: cannot find -lXtst

lc表示libc.solltdl表示libltdl.solXtst表示libXts.so

因此,它是lib + 库名称 + .so


一旦我们知道名称,就可以使用locate找到这个lxxx.so文件的路径。

$ locate libiconv.so
/home/user/anaconda3/lib/libiconv.so   # <-- right here
/home/user/anaconda3/lib/libiconv.so.2
/home/user/anaconda3/lib/libiconv.so.2.5.1
/home/user/anaconda3/lib/preloadable_libiconv.so
/home/user/anaconda3/pkgs/libiconv-1.14-0/lib/libiconv.so
/home/user/anaconda3/pkgs/libiconv-1.14-0/lib/libiconv.so.2
/home/user/anaconda3/pkgs/libiconv-1.14-0/lib/libiconv.so.2.5.1
/home/user/anaconda3/pkgs/libiconv-1.14-0/lib/preloadable_libiconv.so
如果您找不到它,则需要通过yum安装它(我使用CentOS)。通常您有这个文件,但它没有链接到正确的位置。
将其链接到正确的位置,通常是/lib64/usr/lib64$ sudo ln -s /home/user/anaconda3/lib/libiconv.so /usr/lib64/ 完成!
参考:https://i-pogo.blogspot.jp/2010/01/usrbinld-cannot-find-lxxx.html

5
仅当locate被安装并定期运行时才可以使用。一个简单的解决方法是在整个磁盘上运行find,但这会花费时间。如果您经常需要运行此操作,请考虑安装locate以降低(交互式、人为的)成本。 - tripleee
谢谢你的回答,让我明白了出了什么问题。我创建了软链接到“缺失”的 libXXX.so 文件。例如:ln -s libasound.so.2 libasound.so - RyanNerd

7

在编译程序时,您必须提供库的路径;在g++中使用-L选项:

g++ myprogram.cc -o myprogram -lmylib -L/path/foo/bar

1
我们需要在 ccmake 中更改哪个属性,以便创建带有链接标志的 Makefile?我想将我的 -lARToolkitPlus 标志链接到一个路径。 - Shashwat

5

我在一台全新的CentOS 7.8虚拟机上编译LXC时遇到了问题。尝试了以上所有方法都失败了。一些人建议从编译器配置中删除-static标志,但是我不想改变任何东西。

唯一有帮助的方法是安装glibc-static并重试。希望能对某人有所帮助。


也帮了我大忙!:D - ageladas
该死,我在Debian / n00buntu存储库中找不到glibc-static。 - Owl

4

这是我的笔记本电脑的Ubuntu信息。

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.2 LTS
Release:    18.04
Codename:   bionic

我使用 locate 命令查找 boost_filesystem 和 boost_system 的 .so 文件。
locate libboost_filesystem
locate libboost_system

将 .so 文件链接到 /usr/lib 并将其重命名为 .so。
sudo ln -s /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1 /usr/lib/libboost_filesystem.so
sudo ln -s /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 /usr/lib/libboost_system.so

完成了!R包velocyto.R已成功安装!


你不应该手动操作 /usr/lib 中的任何内容;这个目录应该完全由你的包管理器来管理。 - tripleee

3
除了已经给出的答案,可能还存在以下情况:*.so文件存在但命名不正确。或者*.so文件存在但被另一个用户/根用户拥有。
问题1:名称不正确
如果您将文件链接为-l<nameOfLibrary>,则库文件名称必须采用lib<nameOfLibrary>的形式。如果您只有<nameOfLibrary>.so文件,请将其重命名!
问题2:所有者错误
要验证这不是问题,请执行以下操作
ls -l /path/to/.so/file

如果文件归属于root或其他用户,则需要执行以下操作:
sudo chown yourUserName:yourUserName /path/to/.so/file

系统文件显然不应该由您自己拥有。所有权讨论似乎是牵强的;主要问题是库需要是全局可读的(出于安全原因,不能是全局可写的)。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接