静态库(.a库)可以与其他的目标文件(.o文件)一起被连接器连接生成可执行文件,也可以被连接器提取出所需要的目标文件,与其他的目标文件生成动态共享库(so库)。
接下来就来实战模拟一下,将一个静态库连接生成一个动态库的过程。
1 目标
将有一个main.c文件,作为可执行文件的源码文件。
有一个archiveFun.c文件,将被编译成静态库,即.a文件。
有一个soFun.c文件,将被编译成动态库,即.so文件。
他们的依赖关系是:
main.c文件依赖静态库archiveFun.a,静态库libarchiveFun.a依赖动态库libsoFun.so。
2 编写源码文件
2.1 头文件
在include目录下新建头文件:
archiveFun.h
#ifndef C__ARCHIVEFUN_H
#define C__ARCHIVEFUN_H
char* getArchiveFunString();
#endif
soFun.h
#ifndef C__SOFUN_H
#define C__SOFUN_H
char* getSoFunString();
#endif
2.2 源文件
archiveFun.c
#include "include/archiveFun.h"
char* getArchiveFunString(){
return "archiveFunString.william";
}
soFun.c
#include "include/archiveFun.h"
#include "include/soFun.h"
char* getSoFunString(){
return getArchiveFunString();
}
main.c
#include <stdio.h>
#include "include/soFun.h"
int main()
{
char *ret = getSoFunString();
printf("return value=%s",ret);
return 0;
}
3 编译目标文件
gcc -c archiveFun.c soFun.c
分别生成两个.o文件:
archiveFun.o和soFun.o文件。
4 连接生成静态库
libtool -static -o libarchiveFun.a archiveFun.o
由于我的mac机器下执行ar命令会出错,所以改为使用libtool来连接静态库。
生成了libarchiveFun.a库。
5 连接生成动态库
这一步则是将soFun.c的源码打包出来的目标文件,与刚才连接生成的静态库一起进行连接,连接器会在libarchiveFun.a中包含的目标文件中找到soFun.o文件中的未定义的函数,并做一个连接,生成动态库。
gcc -shared soFun.o libarchiveFun.a -o libsoFun.so
生成了动态库libsoFun.so。
我们查看一下这个动态库的符号(注意,macos下的so库不是elf格式的,因此无法使用readelf命令读取mac下编译的so库)
AllProject/CProject/archiveToSharedObject
▶ gobjdump -t libsoFun.so
libsoFun.so: file format mach-o-x86-64
SYMBOL TABLE:
0000000000000f90 g 0f SECT 01 0000 [.text] _getArchiveFunString
0000000000000f80 g 0f SECT 01 0000 [.text] _getSoFunString
0000000000000000 g 01 UND 00 0100 dyld_stub_binder
可以看到so库中有包含了静态库中的函数符号_getArchiveFunString
,说明动态库已经将静态库中的目标文件链接进去了。
6 连接生成可执行文件
6.1 编译生成目标文件
gcc -c main.c
生成了main.o
6.2 将目标文件与so库连接
gcc main.c libsoFun.so -o main
生成了main文件。
执行
./main
输出:return value=archiveFunString.william%
最终工程目录如图: