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

2024-08-28 06:28

本文主要是介绍Linux C/C++ 库链接选项 --whole-archive,--no-whole-archive和--start-group, --end-group,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

库链接选项

  • 一、介绍
    • whole-archive编译选项
    • Bstatic编译选项
    • start-group 编译选项
  • 示例
  • 参考链接

一、介绍

  这四个都是链接器的选项,所以在编译的时候要用-Wl,[options]来传递给链接器,不然编译器会不认得这个选项。
  在大型工程开发中,工程目录会分的非常细,在modules下会创建很多模块,每个modules都会编译成.a静态库文件供主路径/app/src/下使用,这样就会产生链接库问题,比如在app下的函数要调用静态库里的函数,会出现未定义的错误,需要通过:

-Wl,--whole-archive -lXXX
-Wl,--no-whole-archive -lXXX

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

whole-archive编译选项

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

Bstatic编译选项

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

-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格式如下

target_link_libraries(xlibX1.alibX2.alibX3.a
)

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

target_link_libraries(x-Wl,--start-grouplibX3.alibX2.alibX1.a-Wl,--end-group
)

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

示例

// 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 

运行测试:

$ 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:

// 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

这篇关于Linux C/C++ 库链接选项 --whole-archive,--no-whole-archive和--start-group, --end-group的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1113984

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信