当前位置:C++技术网 > 资讯 > Linux编程:5 GCC编译简单快速入门:链接程序库

Linux编程:5 GCC编译简单快速入门:链接程序库

更新时间:2017-01-12 09:23:19浏览次数:1+次

    在《Linux编程GCC编译简单快速入门:编译代码》中,我们已经详细讲述了Linux编译程序的入门知识。本文就对链接库文件进行一番讲述。
    在讲述如何使用GCC链接程序库生成可执行文件前,我们先来看看Linux中的程序库的一些基本常识。
    在Windows中,动态库的后缀名为dll,静态库的后缀名为lib,如cjjjs.dll和cjjjs.lib。在Linux系统中,也指定了常规的后缀名,动态库的后缀名为so,静态库的后缀名为a,如cjjjs.so和cjjjs.a。我们知道,Linux中以文件的X(可执行)属性来区分可执行文件和非可执行文件。而后缀名通常可以提供很多方便的地方,Linux也就有了这样的一个习惯的后缀名了。
    在Windows中,库的名字就是后缀名前面的名字,而Linux则不是这样。如果不了解这一点,刚入手Linux编程,会在这里走弯路。Linux中的库命名的规定是:lib库名.so和lib库名.a 。库名是含在文件名中间的,必须这样。暂时我也不知道为什么,如果你知道,请补充一下。在链接库的时候,一定不要写完整的库文件名,只要写库名即可。
    了解了这些基本常识之后,下面再来说说GCC如何链接动态库。
    假设我们在当前代码目录下有一个动态库libcjjjs.so文件,我们的cjjjs.c文件编译后需要链接cjjjs.so动态库,我们可以使用-l命令实现。
gcc cjjjs.c -o hello -l cjjjs
    这样我们就编译并链接了libcjjjs.so动态库。我们只要在命令选项l(小写的L)后面指定库名即可。l后面可以空格也可不空格。
    上面我们是链接了库,但是没有指定路径。因为我们的动态库是放在当前目录的,而GCC默认是不会在当前目录下搜索动态库文件的,所以会报无法链接文件的错误哦。
    还有一点,GCC默认是优先链接动态库,当在相关的库目录找不到动态库的时候,会尝试寻找静态库链接,如果都找不到,那么就链接失败了。如果我们在上面添加一个-static选项就可以指定链接静态库lib库名.a。比如要链接libcjjjs.a的库文件:
gcc cjjjs.c -o hello -static -l cjjjs
    是不是有一点小疑惑,为什么动态库在编译的时候还需要存在搜索到呢?我们来对照Windows链接情况看看。如果我们以LoadLibrary形式动态加载dll时,我们在写代码时只要包含dll的头文件或者连头文件都不需要,就可以直接编译链接。然而,还有一种形式就是,在生成dll的时候,生成对应的导入lib库。此时我们都不需要LoadLibrary来加载dll,直接就和添加了一个第三方类一样使用dll里的函数。
    类比来看,Linux编译链接依赖动态库的存在,和Windows的dll第二种链接方式有点像。因为gcc需要加载so文件来提取相应的信息,所以需要so文件在链接期间是存在的。
    如果是链接静态库,我们很好理解,因为静态链接就是要将静态库的内容打包到可执行文件里,所以必须在链接时是存在的。
    我们要链接动态库文件,如果在默认的搜索库文件的那些路径没有搜索到的话,就会报链接失败错误。我们这里就会出现这个问题。我们可以使用-L选项来指定库文件所在的目录路径。
gcc cjjjs.c -o hello -L ./ -l cjjjs
    我们这里就指定了在当前目录下搜索库文件,这样就可以成功链接了。
    你会不会好奇,GCC会在哪些目录下搜索库文件呢?又会以什么顺序搜索呢?
    这里又需要特别说明一点,gcc在链接的时候需要搜索动态库或者静态库,在运行的时候也是要搜索动态库的。静态库因为在链接的时候已经打包到可执行文件里了,所以可执行文件在执行的时候,不再搜索静态库了。

    所以,linux链接动态库搜索有两种,一个是链接动态库时搜索,一个是运行时需要加载动态库搜素。这一点需要注意一下,以免混为一谈了。

搜索路径顺序

1.链接时搜索静态库文件和动态库文件

    前面我们说了-L选项后面会跟着一个路径指定动态库或者静态库的位置,自然这个是最先搜索的。如果没有搜索到,gcc就去环境变量LIBRARY_PATH所指示的位置去搜索。如果仍然没有搜索到,则会在系统目录下/lib -> /usr/lib -> /usr/local/lib 寻找。如果还没有找到,就真的找不到了。gcc只会搜索指定的这一层目录,对于这个目录的子目录,是不会递归搜索的。

2.程序运行是搜索加载动态库文件

    那么程序运行的时候,也需要加载动态库运行。所以程序运行时程序加载器会搜索动态库,所以也有一个顺序。首先会在./include搜索,如果没有搜索到,则在环境变量LD_LIBRARY_PATH指定的动态库路径搜索。配置文件/etc/ld.so.conf中指定的动态库搜索路径搜索,然后在默认的动态库搜索路径/lib -> /usr/lib 下搜索。同样这个搜索顺序也是不会在目录下递归搜索子目录的。
    了解了这么多,编译链接和运行可执行程序时的动态库查找问题也就差不多了。如果还有更多问题,我将再进行总结。