Linux 下查找头文件和库的顺序
C语言 — 动态库的两种使用方式说明_动态库的两种调用方式-CSDN博客
linux动态链接库的加载顺序_动态链接库顺序-CSDN博客
几个链接选项
-I
指定头文件搜索目录-L
指定静态库文件搜索目录-Wl,-R(或-Wl,-rpath)
指定动态库文件搜索目录-l
指定库文件-Wl,-rpath
指定运行时动态库路径
区分 LIBRARY_PATH 和 LD_LIBRARY_PATH :
LIBRARY_PATH
环境变量用于在程序编译期间LD_LIBRARY_PATH
环境变量用于在程序加载运行期间
头文件
gcc在编译时按照如下顺序寻找所需要的头文件:
1.先搜索当前目录( 这里注意,只有用#include "headfile.h"
时才会搜索当前目录 )
2.接着搜索-I
指定的头文件目录
3.然后找gcc的环境变量 C_INCLUDE_PATH
,CPLUS_INCLUDE_PATH
,OBJC_INCLUDE_PATH
4.再找内定目录: /usr/include
, /usr/local/include
5.最后找gcc的一系列自带目录,如:
CPLUS_INCLUDE_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
链接静态库文件
gcc在编译时按照如下顺序寻找所需要的库文件:
1.gcc会去找-L
指定的目录
2.再找gcc的环境变量 LIBRARY_PATH
3.再找内定目录
/lib和/lib64
/usr/lib 和/usr/lib64
/usr/local/lib和/usr/local/lib64
这是当初compile gcc时写在程序内的
这里有两个问题:
-
默认情况下,gcc编译时只会查找相应的头文件,而不会链接具体的动态库。也就是说只要include设置完全,就可以编译通过。它没有进一步检查include中的类和函数有没有实现,而是在运行时才开始查找。所以就会经常发生编译可以通过,但运行时却无法运行,因为在运行时它找不到相关类或者函数的实现。
这时可以使用
-Wl,--no-undefined
参数,如果使用了include文件,连接器却找不到相应的实现,就会产生错误提示。 -
编译时默认不查找当前目录,需要使用
-L ./
指定,例如
运行时动态库的搜索路径
gcc编译程序时和程序运行时都需要查找动态链接库的位置。因此对于使用了动态链接库的程序,在链接时 -L
和 -Wl,-rpath
都要用。
在链接时使用-L
标志指明动态链接库的位置告诉编译器在哪里查找库文件,而-rpath
(或-Wl,-rpath
)则是在运行时告诉可执行文件在哪里查找共享库。
动态库的搜索路径搜索的先后顺序是:
- 编译目标代码时指定的动态库搜索路径;这是通过gcc的参数
-Wl,-rpath=
指定。当指定多个动态库搜索路径时,路径之间用冒号:
分隔 - 环境变量
LD_LIBRARY_PATH
指定的动态库搜索路径 - 配置文件
/etc/ld.so.conf
中指定的动态库搜索路径 - 默认的动态库搜索路径
/lib
,/usr/lib
注意:
-
动态库搜寻路径并不包括当前目录,所以当即使可执行文件和其所需的so文件在同一文件夹,也会出现找不到问题
-
一般不推荐直接修改环境变量,而是修改
/etc/ld.so.conf
,将相应的路径添加上,然后ldconfig一下就好 -
ldconfig做的这些东西都与运行程序时有关,跟编译时一点关系都没有,编译的时候还是该加
-L
就得加,不要混淆了 -
往
/lib
和/usr/lib
里面lib,是不用修改/etc/ld.so.conf
的,但是完了之后要调一下ldconfig(很重要),不然这个lib会找不到。而往其他目录加lib,需要修改/etc/ld.so.conf
,并且要ldconfig一下。 -
如果确实需要改环境变量,则有以下几种情况:
- 临时修改(关闭shell后失效):若是权限不够(无法更改
/etc/ld.so.conf
)或只是想临时改一下环境变量用于测试,则可以使用export,就是export一个全局变量LD_LIBRARY_PATH
,然后运行程序的时候就会去这个目录中找lib。如:命令行执行:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/user/abc/lib
一般来讲这只是一种临时的解决方案,在没有权限或临时需要的时候使用。
- 修改作用于当前用户:在
.bashrc
中设置或者在./bash_profile
设置,这对当前用户生效。记得source ~/.bashrc
或source ~/.bash_profile
- 修改作用于所有用户:在
/etc/profile
中设置或在/etc/profile.d/
中创建一个自定义的shell(**.sh
)脚本,一般推荐使用后者。原因如下:
It’s NOT a good idea to change this file unless you know what you are doing. It’s much better to create a custom.sh shell script in
/etc/profile.d/
to make custom changes to your environment, as this will prevent the need for merging in future updates.
翻译即:除非您知道自己在做什么,否则更改此文件不是一个好主意。 最好在/etc/profile.d/
中创建一个自定义的shell(**.sh
)脚本,以对您的环境进行自定义更改,因为这样可以避免在将来的更新中合并。
- 最后是关于环境变量的写法:
如:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/user/abc/lib
或者这样写:export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/home/user/abc/lib"
要用:
隔开,注意要加上$LD_LIBRARY_PATH
,避免之前存在的路径失效,在前则先搜索,在后则后搜索