【C++编译】gcc的-l参数和-L参数

时间:2021-06-28 09:11:16

今天在编译服务的时候,出现了一个错误:

/usr/bin/ld: cannot find -lxxx

于是查了一下,这个错误是因为链接程序ld在指定目录里找不到libxxx.so这个库。

那么,上面所说的“指定目录”是哪些目录,以及 -l的作用是什么呢?

-l参数:用来指定程序要链接的库,-l参数紧接着就是库名。这里的库名并非真正的库文件名。以库名为math的库为例,他的库文件名是libmath.so或者libmath.a(Linux下的库文件都要以lib开头,其中.so是动态库,.a是静态库)。可见,把库文件名的头lib和尾.so去掉就是库名了。

现在,如果我们自已要用到一个第三方提供的库libtest.so,那么我们只要把libtest.so拷贝到/usr/lib里,编译时加上-ltest参数,就能用上libtest.so库了。

实际上,以下两个命令是等价的:

gcc -o mytest mytest.c /usr/lib/libtest.so
gcc -o mytest mytest.c -ltest

放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了(如果是标准C语言库,我们可以不指定其库路径和库名称)。

如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:

/usr/bin/ld: cannot find -lxxx

也就是链接程序ld在那3个目录里找不到libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest。

另外,其实大部分libxxxx.so只是一个链接,比如libm.so链接到/lib/libm.so.6,/lib/libm.so.6又链接到/lib/libm-2.3.2.so,

如果没有这样的链接,则会出错,因为ld只会找libxxxx.so,所以如果你要用到xxxx库,而只有libxxxx.so.x或者libxxxx-x.x.x.so,则做一个链接就可以了:

ln -s libxxxx-x.x.x.so libxxxx.so

当我们需要链接一个库时,手工来写链接参数总是很麻烦的,还好大多数库开发包提供了生成链接参数的程序,名字一般叫xxxx-config,一般放在/usr/bin目录下,比如:

gtk1.2的链接参数生成程序是gtk-config,执行:

gtk-config --libs

就能得到以下输出:

-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic 
-lgmodule -lglib -ldl -lXi -lXext -lX11 -lm

这就是编译一个gtk1.2程序所需的gtk链接参数,xxx-config除了–libs参数外还有一个参数是–cflags,用来生成头文件包含目录的,也就是-I参数。

要使用输出的结果,我们可以复制粘贴或者照抄,不过更好的办法是在编译命令行里加入:

`xxxx-config --libs --cflags`

比如编译一个gtk程序:

gcc gtktest.c `gtk-config --libs --cflags`

注意`不是单引号,而是1键左边那个键。

-include用来包含头文件,但一般情况下包含头文件都在源码里用#include xxxxxx实现,因此-include参数很少用。

-I参数是用来指定头文件目录,/usr/include目录一般是不用指定的,gcc知道去那里找,但是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译命令行就要加上-I/myinclude参数了,如果不加,你会得到一个”xxxx.h: No such file or directory”的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定。

在了解以上内容之后,我们再回过头来看看最开始遇到的问题:

/usr/bin/ld: cannot find -lxxx

发生这种错误的原因有以下三种情形:
1. 系统没有安装相对应的lib
2. 相对应的lib版本不对
3. lib(.so档)的symbolic link 不正确,没有连结到正确的函式库文件(.so)

解决方法:
1. 先判断在/usr/lib 下的相对应的函式库文件(.so) 的symbolic link 是否正确,若不正确改成正确的连结目标即可解决问题。

  1. 若不是symbolic link 的问题引起,而是系统缺少相对应的lib安装lib即可解决。

下面补充下如何生成库文件:

假设有test_a.cpp test_b.cpp两个源文件。

生成so文件的命令:

g++ test_a.cpp test_b.cpp -fPIC -shared -o libtest.so

生成.a文件的命令:

gcc -c test_a.cpp
gcc -c test_b.cpp
ar -r libtest.a test_a.o test_b.o