构建时库文件的定位规则
定位规则基于Linux库文件命名规则,如下:
静态库名 = lib库名.a
动态库名 = lib库名.so<版本>
中间的库名是库的实际名称,链接器在构建时搜索的就是这个名称,装载器在运行时搜索的也是这个名称。
在Linux中使用-L
和-l
指定构建过程中的库文件路径。库文件路径分为两个部分:目录路径和库文件名。这里的库文件名为上述的实际名称。目录路径添加在-L
后,库文件名添加在-l
后。链接libdynamiclib.so
的命令如下:
g++ main.o -L../sharedLib -ldynamiclib -o main
编译链接命令如下:
g++ -fPIC main.cpp -Wl,-L../sharedLib -Wl,-ldynamiclib -o main
也可以简单点:
g++ main.cpp -L../sharedLib -ldynamiclib -o main
-L
只在链接时起作用。-l
后的参数会被嵌入到最终的客户二进制文件(库文件或可执行文件)中,例如上述的main中。-l
在运行阶段也会发挥作用,装载器在读入客户二进制文件后,会跟据-l
后的库文件名来定位,这里的定位为运行时库文件定位。
运行时库文件的定位规则
库搜索顺序:
1 RPATH
2 LD_LIBRARY_PATH
3 RUN_PATH
4 ld.so.cache
5 默认库路径(/lib
和/usr/lib
)
RPATH
本地测试时并没有存在这个字段,无论是否加-Wl,--enable-new-dtags
,都是只有RUN_PATH
这一个字段。
LD_LIBRARY_PATH
为环境变量,命令如下:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../sharedLib
RUN_PATH
为可执行文件中的字段,使用-R
添加该字段:
g++ main.cpp -Wl,-R../sharedLib -L../sharedLib -ldynamiclib -o main
使用readelf -d
查看结果二进制文件main
:
readelf -d main
Dynamic section at offset 0x1d48 contains 30 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [../sharedLib]
0x000000000000000c (INIT) 0x890
0x000000000000000d (FINI) 0xc94
0x0000000000000019 (INIT_ARRAY) 0x201d30
0x000000000000001b (INIT_ARRAYSZ) 16 (bytes)
0x000000000000001a (FINI_ARRAY) 0x201d40
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x298
0x0000000000000005 (STRTAB) 0x470
0x0000000000000006 (SYMTAB) 0x2c0
0x000000000000000a (STRSZ) 418 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0x201f68
0x0000000000000002 (PLTRELSZ) 216 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x7b8
0x0000000000000007 (RELA) 0x698
0x0000000000000008 (RELASZ) 288 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0x638
0x000000006fffffff (VERNEEDNUM) 3
0x000000006ffffff0 (VERSYM) 0x612
0x000000006ffffff9 (RELACOUNT) 4
0x0000000000000000 (NULL) 0x0
ld.so.cache
文件中包含了一组库文件路径列表。可以用下面命令查看
cat /etc/ld.so.cache
可以使用工具ldconfig
将库文件路径添加到ld.so.cache
,这一般是安装软件包的最后一步。