g++ 编译器创建静态和动态链接库

                     

贡献者: addis

  • 本词条处于草稿阶段.
预备知识 C/C++ 多文件编译

   参考这篇文章这篇文章

   事实上,用 apt 安装 lib*-dev 就是在系统的默认搜索路径添加头文件和 lib*.alib*.so 文件,以及它依赖的 package 中的这些文件.这些文件在同一系统版本和同一 cpu 架构都是通用的(运气好的话也可能在不同系统中通用).

1. 静态链接库

   .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),artar 差不多.(其中 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

2. 动态链接库 (*.so)

   创建动态库:

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

   如果同样的 -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

   Linux 程序运行时搜索动态链接库的顺序:

3. 多个动态库

   动态库本身也可以依赖于其他动态库,例如再添加一个程序

// lib0.cpp
#include <iostream>
using namespace std;
int f0()
{
  cout << "In library 0" << endl;
}
然后修改 lib1
// lib1.cpp
#include <iostream>
using namespace std;
int 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 都在.


致读者: 小时百科一直以来坚持所有内容免费,这导致我们处于严重的亏损状态。 长此以往很可能会最终导致我们不得不选择大量广告以及内容付费等。 因此,我们请求广大读者热心打赏 ,使网站得以健康发展。 如果看到这条信息的每位读者能慷慨打赏 10 元,我们一个星期内就能脱离亏损, 并保证在接下来的一整年里向所有读者继续免费提供优质内容。 但遗憾的是只有不到 1% 的读者愿意捐款, 他们的付出帮助了 99% 的读者免费获取知识, 我们在此表示感谢。

                     

友情链接: 超理论坛 | ©小时科技 保留一切权利