UNIX编程-静态库

Posted by 周思进 on September 12, 2021

编译链接

在讲静态库之前,先简单说下程序编译链接的几个步骤:预处理、编译、汇编、链接。

1、预处理主要是处理 “#” 开头的预处理指令,包含插入头文件内容、替换宏、根据编译宏删除无用代码等。

gcc -E test.c -o test.i

2、编译则是生成汇编代码

gcc -S test.i -o test.s

3、汇编则是将汇编代码生成目标文件,即机器可执行的指令

gcc -c test.s -o test.o
objdump -d test.o

4、链接则是最终将各目标文件集合成一个可执行文件,中间涉及符号的重定位等操作

gcc test.o -o test

想要一步到位,则 gcc test.c -o test 即可,自动完成上述四个步骤。

像静态库和动态库都属于第三步生成的成果物,下面来具体说明下静态库的生成步骤。


静态库

静态库其实就是将常用的目标文件打包成一个库文件,也被称为归档文件。其好处就是其他可执行程序如果也需要调用到该库中的接口,直接链接这一个库文件即可,无需再对源码进行编译再一个个链接操作。

下面示例两个源码文件编译成一个静态库

// test1.c
#include <stdio.h>
void test1()
{
    printf("This is test1.\n");
    return ;
}
// test2.c
#include <stdio.h>
void test2()
{
    printf("This is test2.\n");
    return ;
}

先将上述两个源码分别编译成目标文件

gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o

再通过 ar 命令生成静态库,具体操作如下:

ar crs libtest.a test1.o test2.o

选项 c : 创建
选项 r : 增加文件到所创建的库文件中

如果想知道一个静态库是由哪些源码组成,则可以通过选项 -t 直接查看包含了哪些目标文件,也可以使用 -x 选项解压库得到相应的 .o 文件。

如果想直接看这个库有哪些函数实现,可以使用之前介绍的命令 nm


链接静态库

#include <stdio.h>
#include "test1.h"

int main(int argc, char const *argv[])
{
    test1();
    return 0;
}

使用上述程序需要链接到 libtest.a 静态库,链接静态库可以有两种方式

一、当前路径下直接链接

gcc main.c libtest.a

这里静态库的名称是保持原有生成的全名

二、进行库的搜索链接

gcc main.c -L. -ltest

这里库的名称去除了lib前缀和.a后缀,使用 -l 选项指定。同时因为该库不在默认的搜索路径下,需要使用 -L. 指定搜索路径。默认的搜索路径可以通过 echo $PATH 进行查看;如果把库拷贝到默认搜索路径下面,则可以省去 -L 选项。

上面 main.c 函数只使用到了 test1 接口,那链接了 libtest.a 库,是否会将 test2 的实现也链接进来呢? 通过 nm 同样可以查看到并没有。固链接器链接静态库时,只会将程序需要用到的模块包含进来。