C/C++静态库链接原理

前面我们学习了编译链接的一些知识,现在来看看静态库链接的一些知识~

静态库本质上就是使用ar命令打包一堆.o文件:

$ ar -r test.a myObj1.o myObj2.o

静态库没有标准,不同的linux下都会有些细微的差别。大致的格式:

Global header
-----------------        +-------------------------------
File header 1       ---> | File name
File content 1  |        | File modification timestamp 
-----------------        | Owner ID
File header 2            | Group ID
File content 2           | File mode
-----------------        | File size in bytes
...                      | File magic
                         +-------------------------------

链接过程

链接器在链接静态库时,同链接一般的.o基本相似。链接过程大致如下:

这里写图片描述

所有传入链接器的.o都会被链接进最终的可执行程序;链接.o时,会将.o中的global symbol和unresolved symbol放入一个临时表。

如果多个.o定义了相同的global symbol,那么就会得到多重定义的链接错误。

如果链接结束了,unresolved symbol表不为空,那么就会得到符号未定义的链接错误。

.a静态库处理本质上就是处理其中的每一个.o,不同的是,如果某个.o中没有一个符号属于unresolved symbol表,链接器此时怀疑该.o没有必要,它就会被忽略

一些例子

// test.cpp
#include <stdio.h>

class Test {
public:
    Test() {
        printf("Test ctor\n");
    }
};

static Test s_test;
// lib.cpp
#include <stdio.h>

class Lib {
public:
    Lib() {
        printf("Lib ctor\n");
    }
};

static Lib s_lib;
// main.cpp
#include <stdio.h>

int main() {
    printf("main\n");
    return 0;
}

以上代码main.cpp中未引用任何test.cpp和lib.cpp中的符号。

结果如下:

$ g++ -o test test.o lib.o main.o
$ ./test
Lib ctor
Test ctor
main

如果某个.o被链接进程序,那么其文件内的静态变量就会先于main初始化,上面代码中test.o和lib.o都被链接进来了。

但是如果把lib.o以静态库的形式进行链接,情况就不一样了:为了做对比,基于以上的代码再加一个文件,及修改main.cpp:

// libfn.cpp
int sum(int a, int b) {
    return a + b;
}
// main.cpp
#include <stdio.h>

int main() {
    printf("main\n");
    extern int sum(int, int);
    printf("sum: %d\n", sum(2, 3));
    return 0;
}

将libfn.o和lib.o打包为静态库:

$ ar -r libfn.a libfn.o lib.o
$ g++ -o test main.o test.o -lfn -L.
$ ./test
Test ctor
main
sum: 5

main.cpp中未引用任何lib.cpp中的符号,所以lib.o没有被链接,导致其文件内的静态变量也未得到初始化。

调整链接顺序:

# 将libfn.a的链接放在main.o前面

$ g++ -o test test.o -lfn main.o  -L.
main.o: In function `main':
main.cpp:(.text+0x19): undefined reference to `sum(int, int)'
collect2: ld returned 1 exit status

问题在于链接器在链接libfn.a的时候,发现libfn.o中的符号没有被之前链接的*.o引用到,也就是没有任何符号在unresolved symbol table中,所以libfn.o也被忽略。

一些参数

-whole-archive

-whole-archive选项告诉链接器把静态库中的所有.o都进行链接,针对以上例子:

$ g++ -o test -L. test.o -Wl,--whole-archive -lfn main.o -Wl,--no-whole-archive
$ ./test
Lib ctor
Test ctor
main
sum: 5

连lib.o也被链接了进来。-Wl选项告诉gcc将其作为链接器参数传入;之所以在命令行结尾加上–no-whole-archive是为了告诉编译器不要链接gcc默认的库。

–start-group

--start-group archives --end-group

位于–start-group –end-group中的所有静态库将被反复搜索,而不是默认的只搜索一次,直到不再有新的unresolved symbol产生为止。也就是说,出现在这里的.o如果发现有unresolved symbol,则可能回到之前的静态库中继续搜索。

$ g++ -o test -L. test.o -Wl,--start-group -lfn main.o -Wl,--end-group
$ ./test
Test ctor
main
sum: 5

原文地址:http://codemacro.com/2014/09/15/inside-static-library/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值