linux搜索文件顺序
一、预处理时搜索头文件顺序
1、编译脚本指定的-I路径
2、gcc的环境变量(C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH)
3、gcc的安装目录
4、/usr/include
示例如下:
测试源码:
# test.cpp
#include<iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
添加CPLUS_INCLUDE_PATH
vim /etc/profile
export CPLUS_INCLUDE_PATH=/home/tmp1:$CPLUS_INCLUDE_PATH
source /etc/profile
查看结果:
g++ test.cpp --verbose -I/home/tmp
# 结果
...
#include <...> search starts here:
/home/tmp
/home/tmp1
/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0
/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/x86_64-pc-linux-gnu
/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/backward
/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include
/usr/local/include
/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include-fixed
/usr/include
End of search list
...
二、链接时搜索库文件顺序
1、编译脚本指定:-L指定目录,-l指定动态链接库名
2、gcc的安装路径
3、环境变量LIBRARY_PATH (在gcc下编译无效,clang下有效)
4、/lib64或者/lib
5、/usr/lib64或者/usr/lib
6、当前目录
实例如下:
源码:
# test1/test.cpp
# 放在test1目录下
#include<iostream>
using namespace std;
void test()
{
cout << "This is test1" << endl;
}
# test2/test.cpp
# 放在gcc的安装目录下
#include<iostream>
using namespace std;
void test()
{
cout << "This is test22" << endl;
}
# test3/test.cpp
# 放在test3目录下,设置环境变量LIBRARY_PATH为test3目录
#include<iostream>
using namespace std;
void test()
{
cout << "This is test33" << endl;
}
# main.cpp
#include <iostream>
using namespace std;
#include "test.h"
int main()
{
test();
cout << "hello world" << endl;
}
# 编译生成动态库
g++ -c test.cpp -o libtest.so
编译:
# 不显示指定-L
g++ main.cpp -ltest -v
COLLECT_GCC_OPTIONS='-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-pc-linux-gnu/10.2.0/collect2 -plugin /usr/local/libexec/gcc/x86_64-pc-linux-gnu/10.2.0/liblto_plugin.so -plugin-opt=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/10.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/cczIpa36.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /lib/../lib64/crt1.o /lib/../lib64/crti.o /usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtbegin.o -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0 -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L. -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../.. /tmp/ccrLG8PQ.o -ltest -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtend.o /lib/../lib64/crtn.o
从-L可以看出,先找的是gcc的安装目录
# 显示指定-L
g++ main.cpp -L./test1 -ltest -v
COLLECT_GCC_OPTIONS='-L./test1' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/usr/local/libexec/gcc/x86_64-pc-linux-gnu/10.2.0/collect2 -plugin /usr/local/libexec/gcc/x86_64-pc-linux-gnu/10.2.0/liblto_plugin.so -plugin-opt=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/10.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccpha42N.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /lib/../lib64/crt1.o /lib/../lib64/crti.o /usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtbegin.o -L./test1 -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0 -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L. -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../.. /tmp/ccm7u9CG.o -ltest -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtend.o /lib/../lib64/crtn.o
从-L可以看出,先找的是-L指定的test1目录
# clang的情况
clang++ main.cpp -L./test1 -ltest -v
"/usr/bin/ld" --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /lib/../lib64/crt1.o /lib/../lib64/crti.o /usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtbegin.o -L./test1 -L/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/10.2.0 -L/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../lib64 -L/usr/local/bin/../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../.. -L/usr/local/bin/../lib -L/lib -L/usr/lib -L/home/test3 -L/home/test3 -L. /tmp/main-b5ac75.o -ltest -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/10.2.0/crtend.o /lib/../lib64/crtn.o
也是先找的-L指定的目录,然后是安装目录,接着是LIBRARY_PATH目录。
三、运行时搜索库文件顺序
1、rpath(编译代码时指定的动态库搜索路径)
如果在编译时制定了这个路径,在linux的elf文件中会有对应路径,表示了可执行文件或者动态库在运行时首先查到动态库的路径。
指定路径的方式是:(cmake的方式不同,这里就不记录了)
-Wl,--rpath /libpath1:/libpath2 # elf生成RPATH
-Wl,--disable-new-dtags,--rpath /libpath1:/libpath2 # elf生成RPATH
-Wl,--enable-new-dtags,--rpath /libpath1:/libpath2 # elf生成RUNPATH
2、LD_LIBRARY_PATH指定的路径
3、runpath(也是在编译时指定)
生成的elf文件中会有该路径
-Wl,--enable-new-dtags,--rpath /libpath1:/libpath2 # elf生成RUNPATH
4、配置文件/etc/ld.so.conf指定的路径(这里修改完后需要执行ldconfig,使得重新加载下文件中指定的路径)
5、/lib64或/lib
6、/usr/lib64或/usr/lib
实例:
源码同样是上述例子,编译成libtest.so的时候,注意采用如下脚本:
# 得到.o
g++ -c test.cpp -fPIC -o test.o
# 得到.so
g++ -shared -o libtest.so test.o
# 指定了rpath
g++ main.cpp -L./test1 -ltest -v -Wl,-rpath ./test1
# 查看动态库搜索路径
ldd ./a.out
linux-vdso.so.1 => (0x00007ffcf132e000)
libtest.so => ./test1/libtest.so (0x00007f98d9081000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f98d8cb4000)
libm.so.6 => /lib64/libm.so.6 (0x00007f98d89b2000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f98d879b000)
libc.so.6 => /lib64/libc.so.6 (0x00007f98d83ca000)
/lib64/ld-linux-x86-64.so.2 (0x00007f98d9283000)
# 查看.dynamic段的内容
readelf -d ./a.out
Dynamic section at offset 0xdd8 contains 29 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libtest.so]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000f (RPATH) Library rpath: [./test1]
0x000000000000000c (INIT) 0x400718
0x000000000000000d (FINI) 0x4009b4
0x0000000000000019 (INIT_ARRAY) 0x600dc0
0x000000000000001b (INIT_ARRAYSZ) 16 (bytes)
0x000000000000001a (FINI_ARRAY) 0x600dd0
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x0000000000000004 (HASH) 0x400278
0x0000000000000005 (STRTAB) 0x400450
0x0000000000000006 (SYMTAB) 0x4002d0
0x000000000000000a (STRSZ) 374 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x601000
0x0000000000000002 (PLTRELSZ) 192 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x400658
0x0000000000000007 (RELA) 0x400628
0x0000000000000008 (RELASZ) 48 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000006ffffffe (VERNEED) 0x4005e8
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x4005c6
0x0000000000000000 (NULL) 0x0
由ldd结果可见,运行时使用到的库是RPATH指定的库。
使用如下脚本更换为RUNPATH
g++ main.cpp -L./test1 -ltest -v -Wl,enable-new-dtags,-rpath ./test2
通过readelf查看,结果也是肯定的。
0x0000000000000001 (NEEDED) Shared library: [libtest.so]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libm.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [./test2]
接着,更改LD_LIBRARY_PATH,试着修改查找顺序。
export LD_LIBRARY_PATH=/home/tmp/test1:$LD_LIBRARY_PATH
ldd ./a.out
linux-vdso.so.1 => (0x00007ffe481be000)
libtest.so => /home/tmp/test1/libtest.so (0x00007fd2b5350000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fd2b4f83000)
libm.so.6 => /lib64/libm.so.6 (0x00007fd2b4c81000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd2b4a6a000)
libc.so.6 => /lib64/libc.so.6 (0x00007fd2b4699000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd2b5552000)
可见,原先的查找顺序已经被覆盖了。而RPATH不会被覆盖。
同样,可以在不同目录下放入libtest.so文件,然后逐个删除,看下具体的依赖顺序,具体不再贴上了。
总之:上面说的查询顺序是对的。
- 点赞
- 收藏
- 关注作者
评论(0)