1. 参数介绍

1.1 -i( -include:i 的小写) :包含头文件名字

  • 用来包含头文件名字,但一般情况下包含头文件都在源码里#include xxxxxx实现,-include参数很少用 (一般不使用,而是直接放在**.c 文件中通过#include<***.h> 添加);

1.2 -I

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

1.2 -l

  • 指定需要链接的库的名字(链接 libc.a :-lc 链接动态库:libc.so : -lc 注意:-l后面直接添加库名省区“lib”和“.so”或“.a” );

1.2 -L

  • 指定连接的动态库或者静态库路径(相对路径或觉得路径,建议相对路径) ;

2. 搜索路径

2.1 静态库链接时搜索路径顺序

  • ld会去找GCC命令中的参数-L
  • 再找gcc的环境变量LIBRARY_PATH (用法:LIBRARY_PATH= path
  • 再找内定目录 /lib/usr/lib/usr/local/lib这是当初compile gcc时写在程序内的 (因系统版本而定 :/lib64)

2.2 动态库链接时、执行时搜索路径顺序

  • 去找GCC命令中的参数-L
  • 环境变量LD_LIBRARY_PATH指定的动态库搜索路径 (LD_LIBRARY_PATH=path
  • 配置文件/etc/ld.so.conf中指定的动态库搜索路径 (修改/etc/ld.so.conf文件,将路径添加进去,运行/sbin/ldconfig
  • 默认的动态库搜索路径/lib(因系统版本而定:/lib64
  • 默认的动态库搜索路径/usr/lib(因系统版本而定)

2.3 头文件搜索路径

  • -I( i 的大写 ) 指定的路径
  • 源程序头(#include "")文件中指定的路径
  • /usr/include
  • /usr/local/include

2.4 静态库、动态库环境变量

  • LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
  • LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径

3. -Wl,-rpath选项

  • -Wl,-rpath=<动态库文件位置> ,是为程序添加一个运行时库文件搜索路径的命令,在使用gcc编译链接时添加即可。即通过-Wl,-rpath=《lib_path》可添加文件夹作为动态库搜索路径,并记录在程序ELF可执行程序中。我们调用程序时会去我们写入的目录中查找的第三方库文件;-并非指定-rpath参数后,就抛弃LD_LIBRARY_PATH环境变量,只是多了个可选的依赖库路径而已。LD_LIBRARY_PATH不仅指定可执行文件的库路径,还指定了库所依赖其它库的路径
  • 假设main.cpp、hello.h、hello.cpp,其中main.cpp调用了hello类中的方法
  • 使用linux编写c/c++程序时,需要用到第三方的动态库文件。刚开始编译完后,运行提示找不到动态库文件。我就使用了ldd命令查看了一下,发现是有一个库文件显示”not found”,如下图所示;
  • 其中,有两个单独的部分-Wl-rpath组成。
  • -Wl
      这个是gcc的参数,表示编译器将后面的参数传递给链接器ld。请注意此处的W是大写的。
  • -rpath
      使用man ld命令查看手册,找到了-rpath的讲解:运行可执行文件时路径有效(链接器已经将库的路径包含在可执行文件中了)
  • -rpath-link:
      运行可执行文件时指定的路径不再有效(链接器没有包含进可执行文件中)
gcc test.c -lhello  -L . -Wl,-rpath-link ./lib_tmp
  • -rpath-rpath-link都可以在链接时指定库的路径;但是运行可执行文件时-rpath-link指定的路径就不再有效(链接器没有包含进可执行文件中),而-rpath指定的路径还有效(因为链接器已经将库的路径包含在可执行文件中了)。 最后,不管使用了-rpath还是-rpath-linkLD_LIBRARY_PATH还是有效的

3.1 生成hello.so

g++ -shared hello.cpp -o libhello.so

3.2 编译main.cpp、链接、指定运行时链接库(libhello.so)的位置

g++ main.cpp -lhello -L./ -Wl,-rpath=./ -o main

3.3 带版本号的动态库

  • 例如libhello.so.2,链接命令可使用
g++ main.cpp libhello.so.2 -L./ -Wl,-rpath=./ -o main

3.4 加入第二个so库

g++ main.cpp -L./second/ -Wl,-rpath=./second/ -lsecond -L./hello/ -Wl,-rpath=./hello/ -lhello -o main

4. 可能问题

4.1 对于库文件未找到

  • 因为编译链接都没有问题,那运行链接动态库时找不到动态库了。对于运行链接动态库时找不到动态库的方法,最基本的解决方法四种

4.1.1 第一种方法(找到so放到/lib、/usr/lib目录中)

  • 找到缺少的动态库(由于编译链接时候的使用到了这个动态库,所以很容易找得到),将其加到/lib、/usr/lib/usr/local/lib中的一个文件夹下,这几个文件夹是系统默认的搜索路径。将库文件放置在其中,运行时就可以搜索到了。

4.1.2 第二种方法(设置临时增加链接动态库的路径)

  • 使用命令行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:《your_lib_path》
  • 比如我的libhello.so/home/huyf/myapp/lib目录下,那我使用的是:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/huyf/myapp/lib
  • 这种方法设置的是临时的,系统重启之后没了。当然也可以设置为持久的,这里就不过多讲述。

4.1.3 第三种方法(更改配置文件)

  • /etc/ld.so.cache缓存动态库路径,可以通过修改配置文件/etc/ld.so.conf中指定的动态库搜索路径,然后执行ldconfig命令来改变。
  • 不过,我又想了一下,感觉这几种方法都不适合我现在的情况,这些都是事后补救的方法。首先,我不可能每次需要用到一个第三方的动态库的时候都要往几个系统默认的文件夹里面扔,这会导致这几个文件夹越来越大,越来越乱;再者,我也不想每次都设置临时动态库搜索路径,每个程序这么做的话得设置多少次啊,而且也导致文件夹变多,总归不好;而更改配置我就更不推荐了,会导致配置文件越来越乱。

4.1.4 第四种方法(在链接时使用-Wl,-rpath命令)

-Wl,-rpath=《my_thirdparty_lib_path》

4.2 -l(L的小写)链接的到底是动态库还是静态库?

如果链接路径下同时有 .so 和 .a 那优先链接 .so

4.3 如果路径下同时有静态库和动态库如何链接静态库?

  • 使用显示链接, gcc -l:lib***.a (将静态库的名字显示写出来)或者在 gcc 编译的时候 加入参数 -static -lxxx, 则可以添加路径下面的静态库。比如同一目录下有libxxx.a文件和libxxx.so文件,gcc默认会链接xxx.so,改变这一默认行为的方法就是:将"-lxxx"改为"-l:libxxx.a",或者-static -lxxx,把.a它当.o文件一样链接
  • 验证方法:
    可以通过 ldd 命令查看生成的目标文件链接的库,使用方法: ldd ***.o