静态库(.a库)可以与其他的目标文件(.o文件)一起被连接器连接生成可执行文件,也可以被连接器提取出所需要的目标文件,与其他的目标文件生成动态共享库(so库)。
image.png

接下来就来实战模拟一下,将一个静态库连接生成一个动态库的过程。

1 目标

将有一个main.c文件,作为可执行文件的源码文件。
有一个archiveFun.c文件,将被编译成静态库,即.a文件。
有一个soFun.c文件,将被编译成动态库,即.so文件。

他们的依赖关系是:
main.c文件依赖静态库archiveFun.a,静态库libarchiveFun.a依赖动态库libsoFun.so。

2 编写源码文件

2.1 头文件

在include目录下新建头文件:

archiveFun.h

  1. #ifndef C__ARCHIVEFUN_H
  2. #define C__ARCHIVEFUN_H
  3. char* getArchiveFunString();
  4. #endif

soFun.h

  1. #ifndef C__SOFUN_H
  2. #define C__SOFUN_H
  3. char* getSoFunString();
  4. #endif

2.2 源文件

archiveFun.c

  1. #include "include/archiveFun.h"
  2. char* getArchiveFunString(){
  3. return "archiveFunString.william";
  4. }

soFun.c

  1. #include "include/archiveFun.h"
  2. #include "include/soFun.h"
  3. char* getSoFunString(){
  4. return getArchiveFunString();
  5. }

main.c

  1. #include <stdio.h>
  2. #include "include/soFun.h"
  3. int main()
  4. {
  5. char *ret = getSoFunString();
  6. printf("return value=%s",ret);
  7. return 0;
  8. }

项目目录结构如下
image.png

3 编译目标文件

  1. gcc -c archiveFun.c soFun.c

分别生成两个.o文件:
archiveFun.o和soFun.o文件。

4 连接生成静态库

  1. libtool -static -o libarchiveFun.a archiveFun.o

由于我的mac机器下执行ar命令会出错,所以改为使用libtool来连接静态库。
生成了libarchiveFun.a库。

5 连接生成动态库

这一步则是将soFun.c的源码打包出来的目标文件,与刚才连接生成的静态库一起进行连接,连接器会在libarchiveFun.a中包含的目标文件中找到soFun.o文件中的未定义的函数,并做一个连接,生成动态库。

  1. gcc -shared soFun.o libarchiveFun.a -o libsoFun.so

生成了动态库libsoFun.so。
我们查看一下这个动态库的符号(注意,macos下的so库不是elf格式的,因此无法使用readelf命令读取mac下编译的so库)

  1. AllProject/CProject/archiveToSharedObject
  2. gobjdump -t libsoFun.so
  3. libsoFun.so: file format mach-o-x86-64
  4. SYMBOL TABLE:
  5. 0000000000000f90 g 0f SECT 01 0000 [.text] _getArchiveFunString
  6. 0000000000000f80 g 0f SECT 01 0000 [.text] _getSoFunString
  7. 0000000000000000 g 01 UND 00 0100 dyld_stub_binder

可以看到so库中有包含了静态库中的函数符号_getArchiveFunString,说明动态库已经将静态库中的目标文件链接进去了。

6 连接生成可执行文件

6.1 编译生成目标文件

  1. gcc -c main.c

生成了main.o

6.2 将目标文件与so库连接

  1. gcc main.c libsoFun.so -o main

生成了main文件。
执行

  1. ./main

输出:return value=archiveFunString.william%

最终工程目录如图:
image.png