贡献者: addis
ldd 可执行文件 可以查看一个程序使用的所有动态链接库,包括库所依赖的其他库
/usr/local/lib, /usr/local/lib64, /usr/lib and /usr/lib64
事实上,用 apt 安装 lib*-dev 就是在系统的默认搜索路径添加头文件和 lib*.a,lib*.so 文件,以及它依赖的 package 中的这些文件.这些文件在同一系统版本和同一 cpu 架构都是通用的(运气好的话也可能在不同系统中通用).
.a 文件是 static library, 在编译的时候一起编入可执行文件. 下面举一个例子
// lib1.cpp
#include <iostream>
using namespace std;
int f1()
{ cout << "In library 1" << endl; }
再编一个主文件
// main.cpp
#include <iostream>
using namespace std;
void f1();
int main()
{
f1();
cout << "In main" << endl;
}
如果将这两个文件用 g++ 正常编译 g++ main.cpp lib1.cpp 执行结果为
In library 1
In main
但现在我们把 lib1.cpp 先编译成 .o 文件
g++ -static -c -o lib1.o lib1.cpp
(其实 -o lib1.o 可以省略)(-static 用于静态编译), 再从 .o 文件生成 .a 文件 .a 文件的命名规则一般是前面加 (lib*.a)
ar rcs lib1.a lib1.o
可以将多个 .o 文件封装到 .a 里面, 在后面添加 lib2.o, lib3.o 等即可..a 就是 .o 的压缩文件(archive),ar 和 tar 差不多.(其中 rcs 选项中的 r 选项是添加并替换旧文件(如果有同名), c 选项是 create archive, s 选项是 write out an index, 虽然还是不明白什么意思).若要打印文件内容,用 ar p lib1.a 或者 ar pv lib1.a(verbose).若要取出所有文件,用 ar x lib1.a [文件1] [文件2].
再来将 lib1.a 和主程序文件一块编译
g++ main.cpp -o main.x -L./ -l 1
其中 -o 的作用是给生成的可执行文件命名, -L 的作用是声明 .a 所在的目录, -l 是指明所用的 .a 文件, (将 lib*.a 写成 * 即可).
现在就可以运行 main.x 了
./main.x
.a 就是 archive 的 .o 文件.在 link 阶段使用.
g++ 在 link 阶段 .o 或 .a 的顺序是非常重要的,某个 o 文件只能调用在它后面列出的 o 文件,否则会提示找不到 symbol.要让 g++ 忽略这个顺序,可以使用
-Wl,--start-group 文件1 文件2 ... -Wl,--end-group,这样 linker 找不到 symbol 时就会在 group 内的文件中反复搜索(编译速度会降低).
g++ 手册吧.
创建动态库:
g++ -shared -fPIC -o lib1.so lib1.cpp
使用方法:
把 cpp 编译成 .o 文件时不需要声明动态链接库和所在目录, -c 选项普通编译即可.
g++ -c main.cpp
把 .o 文件链接成可执行文件时, 在最后 (注意必须是在最后) 加上
-Wl,-rpath,<library path> -L<library path> -l <libname1> -l <libname2>
其中 -Wl,aaa,bbb 命令是将 aaa bbb 选项传给 linker, 剩下的 -L<library path> -l <libname1> -l <libname2> 的用法和上述 .a 中的一样.
g++ -o main.x main.o -l1 -L./ -Wl,-rpath,./
可以用 ldd main.x 查看动态链接库,会发现其中有 lib1.so.如果不用 rpath,也可以在执行可执行文件以前把路径加入到环境变量 LD_LIBRARY_PATH 中.rpath 可以是相对于可执行文件的相对路径,也可以是绝对路径.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/your/custom/path/
rpath 只能设定当前可执行文件的的路径,如果可执行文件依赖的 .so 文件所需要的 .so 文件不在默认路径,就只能通过修改 LD_LIBRARY_PATH 才可以.
rpath,设置环境变量 LD_RUN_PATH 也是等效的.链接的程序是 ld,而动态链接库是 ld-linux.so
chrpath 或者 patchelf 参考这里.
-l 既能匹配 lib***.a 也能匹配 lib***.so,那么 gcc 会默认选 .so(貌似有时候二者都需要).如果想要静态链接,要么用 -static 选项(禁止链接到任何动态 lib),要么直接指定 .a 的地址和文件名,如 g++ -o main.x f1.o /some/path/lib***.a another/path/lib***.a.
.a 或 .so 文件里面是否有某个函数,用例如 nm -A /usr/lib/x86_64-linux-gnu/libflint.a | grep fmpz_set 类似地也有 nm xxx.so
rpath 是相对路径,那么它相对的是 pwd 而不是可执行文件的位置,定义时可以使用 ${ORIGIN} 来表示可执行文件的位置.
Linux 程序运行时搜索动态链接库的顺序:
LD_LIBRARY_PATH
rpath
/lib/ 和 /usr/lib/ 中的,以及 /etc/ld.so.conf 中的文件
ld --verbose | grep SEARCH_DIR | tr -s ' ;' \\012 可以查看 linker 的默认搜索路径
sudo ldconfig 可以更新动态链接库的搜索
动态库本身也可以依赖于其他动态库,例如再添加一个程序
// lib0.cpp
#include <iostream>
using namespace std;
void f0()
{
cout << "In library 0" << endl;
}
然后修改 lib1
// lib1.cpp
#include <iostream>
using namespace std;
void f1()
{
cout << "In library 1" << endl;
void f0();
f0();
}
制作库
g++ -c lib0.cpp lib1.cpp // 生成 lib0.o lib1.o
g++ -shared -fPIC -o lib0.so lib0.cpp
g++ -shared -fPIC -o lib1.so lib1.cpp -l0 -L./ -Wl,-rpath,./
编译主程序,使用库,注意只需要链接 lib1
g++ -c main.cpp
g++ -o main.x main.o -l1 -L./ -Wl,-rpath,./
用 ldd main.x 检查所有依赖的动态库,会发现 lib0, lib1 都在.
 
 
 
 
 
 
 
 
 
 
 
友情链接: 超理论坛 | ©小时科技 保留一切权利