Linux C/C++ 库链接选项 --whole-archive,--no-whole-archive和--start-group, --end-group

库链接选项

一、介绍

这四个都是链接器的选项,所以在编译的时候要用-Wl,[options]来传递给链接器,不然编译器会不认得这个选项。

在大型工程开发中,工程目录会分的非常细,在modules下会创建很多模块,每个modules都会编译成.a静态库文件供主路径/app/src/下使用,这样就会产生链接库问题,比如在app下的函数要调用静态库里的函数,会出现未定义的错误,需要通过:

powershell 复制代码
-Wl,--whole-archive -lXXX
-Wl,--no-whole-archive -lXXX

在脚本里修改下链接库的选项,这里XXX代表静态库的名称。

whole-archive编译选项

默认情况下,对于未使用到的符号(函数是一种符号),链接器不会将它们链接进共享库和可执行程序。这个时候,可以启用链接参数 "--whole-archive"来告诉链接器,将后面库中所有符号都链接进来,参数 "-no-whole-archive" 则是重置,以避免后面库的所有符号被链接进来。

Bstatic编译选项

"-Wl,-Bstatic"指定链接静态库,使用"-Wl,-Bdynamic"指定链接共享库,使用示例:

powershell 复制代码
-Wl,-Bstatic -lmysqlclient_r -lssl -lcrypto -Wl,-Bdynamic -lrt -Wl,-Bdynamic -pthread -Wl,-Bstatic -lgtest

start-group 编译选项

假设程序x依赖三个静态库:libX1.a、libX2.a和libX3.a,而libX2.a又依赖libX1.a,libX3.a依赖libX2.a和libX1.a,正常情况下的CMakeLists.txt格式如下

powershell 复制代码
target_link_libraries(
    x
    libX1.a
    libX2.a
    libX3.a
)

但也不关心静态库的顺序问题,ld为此提供了start-group和end-group两个选项,让包含在这两者间的静态库顺序可以随意。

powershell 复制代码
target_link_libraries(
    x
    -Wl,--start-group
    libX3.a
    libX2.a
    libX1.a
    -Wl,--end-group
)

这里有一个链接顺序的问题,在command line上前面的库会依赖之后的库,如果碰到循环链接,-lliba -llibb -lliba,这样就需要使用--start-group和--end-group反复在.a中进行搜索直到所有的未定义字符都被找到为止,而不是默认的只搜索一次。MKL库有这样的问题。

示例

cpp 复制代码
// a.h   
extern void foo();
 
// a.cpp 
#include  
void foo() 
{ 
	printf("foo\n"); 
} 

// x.cpp 
#include "a.h" 
int main() 
{ 
	foo(); 
	return 0; 
}

// Makefile 
all: x 
x: x.cpp liba.so 
	g++ -g -o $@ $^ 
liba.so: liba.a 
 	g++ -g -fPIC -shared -o $@ $^ 
 	#g++ -g -fPIC -shared -o $@ -Wl,--whole-archive $^ -Wl,-no-whole-archive 
liba.a: a.o 
 	ar cru $@ $^ 
a.o: a.cpp 
 	g++ -g -c $^ 
clean: 
 	rm -f x a.o liba.a liba.so 

运行测试:

powershell 复制代码
$ make 
 	g++ -g -c a.cpp 
 	ar cru liba.a a.o 
 	g++ -g -fPIC -shared -o liba.so liba.a 
 	#g++ -g -fPIC -shared -o liba.so -Wl,--whole-archive liba.a -Wl,-no-whole-archive 
 	g++ -g -o x x.cpp liba.so 
 	/tmp/cc6UYIAF.o: In function `main': 
 	/data/jayyi/ld/x.cpp:5: undefined reference to `foo()' 
 	collect2: ld returned 1 exit status 
 	make: *** [x] Error 1 

默认情况下,对于未使用到的符号(函数是一种符号),链接器不会将它们链接进共享库和可执行程序。

这个时候,可以启用链接参数"--whole-archive"来告诉链接器,将后面库中所有符号都链接进来,参数"-no-whole-archive"则是重置,以避免后面库的所有符号被链接进来。

主要作用就是解决主目录函数与模块间函数相互调用问题。

修改一下makefile:

bash 复制代码
// Makefile 
all: x 
x: x.cpp liba.so 
 	g++ -g -o $@ $^ 
liba.so: liba.a 
 	g++ -g -fPIC -shared -o $@ -Wl,--whole-archive $^ -Wl,-no-whole-archive 
liba.a: a.o 
 	ar cru $@ $^ 
a.o: a.cpp 
 	g++ -g -c $^ 
clean: 
 	rm -f x a.o liba.a liba.so 

参考链接

https://www.cnblogs.com/vaughnhuang/p/16474361.html

https://blog.csdn.net/lanhuazui10/article/details/107895036

https://www.cnblogs.com/JimmyTY/p/5856217.html

相关推荐
阿俊仔(摸鱼版)3 分钟前
Python 常用运维模块之Shutil 模块
linux·服务器·python·自动化·云服务器
zhangxueyi10 分钟前
如何理解Linux的根目录?与widows系统盘有何区别?
linux·服务器·php
可涵不会debug10 分钟前
C语言文件操作:标准库与系统调用实践
linux·服务器·c语言·开发语言·c++
ghx_echo13 分钟前
linux系统下的磁盘扩容
linux·运维·服务器
刘好念37 分钟前
[OpenGL]实现屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO)
c++·计算机图形学·opengl·glsl
幻想编织者1 小时前
Ubuntu实时核编译安装与NVIDIA驱动安装教程(ubuntu 22.04,20.04)
linux·服务器·ubuntu·nvidia
利刃大大2 小时前
【Linux入门】2w字详解yum、vim、gcc/g++、gdb、makefile以及进度条小程序
linux·c语言·vim·makefile·gdb·gcc
C嘎嘎嵌入式开发2 小时前
什么是僵尸进程
服务器·数据库·c++
我想学LINUX3 小时前
【2024年华为OD机试】 (A卷,100分)- 微服务的集成测试(JavaScript&Java & Python&C/C++)
java·c语言·javascript·python·华为od·微服务·集成测试
雁于飞3 小时前
c语言贪吃蛇(极简版,基本能玩)
c语言·开发语言·笔记·学习·其他·课程设计·大作业