天天看点

5.15 vs2019 静态编译_链接过程中静态库先后顺序的影响分析

问题描述

项目中准备引入redis,采用acl的c++库对redis进行访问。acl的示例代码如下所示

#include 
           

对示例代码进行编译链接

`
           

报了许多链接的错误

(aio_listen_stream.o
           

问题分析

acl和acl_cpp均为静态库,acl是最基础的库,以C语言实现,其它库均依赖于该库; acl_cpp库用C++封装了acl库,提供给C++程序调用。

链接错误集中表现为acl_cpp库引用了acl库中的函数但未能找到其定义。

问题解决

在编译命令的参数中已给出了acl库的路径和名称,不应该找不到。尝试把acl_cpp库在命令行中的顺序放在acl库之前

`
           

顺利编译通过。

原理探究

创建一个示例工程,包含main.c、comp1_func1.c、comp1_func2.c、comp2_func1.c四个文件,其函数调用关系如下所示:

5.15 vs2019 静态编译_链接过程中静态库先后顺序的影响分析
  • 编译main.c
0000000000000000         *UND*  
           

main.o中有两个未定义的符号:comp1_func1和comp2_func1

  • 编译静态库
0000000000000000 g     F .text  000000000000000e comp1_func1

comp1_func2.o:     文件格式 elf64-x86-64
           

libcomp2.a中有一个未定义的符号comp1_func2

  • 增量链接 将main.o和libcomp1.a先进行链接
0000000000000000 l    df *ABS*  
           

链接器并不是把静态库文件看做一个整体,而是将打包在其中的目标文件(.o)作为链接单元。在链接过程中,如果某个目标文件中的符号被用到了,那么这个目标文件会单独从库文件中提取出来并入可执行程序,而其余的目标文件则会被丢弃。

main.o中引用了libcomp1.a中comp1_func1.o的comp1_func1函数,因此将comp1_func1.o并入,而comp1_func2.o中的comp1_func2函数未被引用,因此被丢弃。

  • 全量链接 将main.o和libcomp1.a、libcomp2.a进行链接
0000000000000000         *UND*  
           

libcomp2.a中引用的comp1_func2函数虽然已在libcomp1.a中定义,但由于comp1_func2.o被丢弃,导致该函数找不到定义

0000000000000021 g     F .text  000000000000000e comp1_func1
           

整个分析的过程可参考下图:

5.15 vs2019 静态编译_链接过程中静态库先后顺序的影响分析

将静态库的顺序调换后,所有符号都找到了定义。所以在链接静态库的时候,应该将被依赖的库放在最右边。

继续阅读