静态链接库顺序问题

news2025/4/19 18:28:16

前言

最近遇到了一个非常奇怪的问题,编译时竟因为链接库的顺序不同,就有完全不同的结果。代码非常简单如下所示:

#include "muduo/net/EventLoop.h"

int main() {
    muduo::net::EventLoop loop1;
    muduo::net::EventLoop loop2;
    return 0;
}

只是在一个线程内创建两个 EventLoop 对象,这是不被允许的,应该会报错。我使用如下命令编译:

g++ test.cc -I ../include -L ../lib -lpthread -lmuduo_base -lmuduo_net

此时却报了一堆未定义错误:

EventLoop.cc:205: undefined reference to `muduo::Logger::Logger(muduo::Logger::SourceFile, int, muduo::Logger::LogLevel)'
EventLoop.cc:205: undefined reference to `muduo::LogStream::operator<<(long)'
EventLoop.cc:205: undefined reference to `muduo::Logger::~Logger()'

这些东西都是在 muduo_base 中定义的,我明明链接的 muduo_base 库,为什么会有这些报错呢?当我改变链接库的顺序时,神奇的一幕出现了。

qgw@virtual-machine:~/build/release-install-cpp11/examples$ make
g++ echo.cc -I ../include -L ../lib -lpthread -lmuduo_net -lmuduo_base
qgw@virtual-machine:~/build/release-install-cpp11/examples$ ./a.out 
20230529 06:44:22.218800Z  5020 DEBUG EventLoop EventLoop created 0X7FFFD30BDFB0 in thread 5020 - EventLoop.cc:65
20230529 06:44:22.218835Z  5020 DEBUG EventLoop EventLoop created 0X7FFFD30BE050 in thread 5020 - EventLoop.cc:65
20230529 06:44:22.218837Z  5020 FATAL Another EventLoop 0X7FFFD30BDFB0 exists in this thread 5020 - EventLoop.cc:68
已放弃 (核心已转储)

编译成功了,运行程序也得到了我想要的结果。这究竟是为什么呢?下面就来为你解答这一迷题。

理论基础

编译过程

先来简单了解下,从我们编写的程序到形成可执行程序的过程。大致可以分为 4 个步骤,分别是预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。

compilation process

经过编译、汇编形成的目标文件并不能直接执行,它首先需要载入到链接器中。链接器确认 main 函数为初始进入点,把符号引用绑定到内存地址,把所有的目标文件集中在一起,再加上库文件,从而产生可执行文件。

静态链接

动态链接是将函数库加载到进程地址空间,程序在运行时寻找它们,而不是把函数库二进制代码作为自身可执行程序的一部分。

如果函数库的一份副本是可执行文件的物理组成部分,那么我们称之为静态链接。简单点说,就是静态链接需要将我们用到的函数代码,拷贝到可执行程序中,之后就不再需要库了。

这两者在提取符号上有很大的不同:

在动态链接中,所有的库符号加载到输出文件的虚拟地址空间中,所有的符号对于链接在一起的所有文件都是可见的。

在静态链接中,在处理静态库时,它只是在静态库中查找载入器当前所知道的未定义符号。换句话说,在编译器命令行中各个静态链接库的顺序是非常重要的。

链接器会被「函数库是在哪里提到的?」「它是以什么次序出现的?」之类的问题搞的晕头转向,因为符号是通过从左到右的顺序进行解析的。在尚未出现未定义的符号时,它不会从函数库中提取任何符号。为了能从静态库中提取所需的符号,首先需要让文件包含未解析的引用。

解答

有上面的知识,开头的问题也就很好解释了。muduo 使用的是静态库,在最开始的时候,我先链接了 muduo_base 库,又链接了 muduo_net 库。

程序中只有 EventLoop 一个未定义的符号,扫描到 muduo_base 库,此时并没有能从该库提取的符号,继续扫描到 muduo_net 库,找到了 EventLoop 符号。由于 EventLoop 中用到 Logger 打印日志、Timestamp 记录时间等等。这些符号都是在 muduo_base 中定义的,但 muduo_base 已经扫描过了,向后寻找也没找到这些符号的定义,于是出现了未定义错误。

当我改变链接顺序时,先扫描 muduo_net 找到了大量定义于 muduo_base 的符号,再扫描 muduo_base 找到这些符号的定义,也就编译成功了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/587562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Tomcat之多JAVA环境JVM版本查看及使用优先级

一、前言 业务系统包含PC端和移动端&#xff0c;移动端为微信小程序。在小程序客户端发送消息未得到回应&#xff0c;查询系统后台日志发现报错日志。JDK或者JRE中自带的“local_policy.jar ”和“US_export_policy.jar”是支持128位密钥的加密算法&#xff0c;而当我们要使用2…

Linux开发工具vim篇

文章目录 &#x1f447;0. 前言&#x1f449;1.yum软件包管理器&#x1f44f;1.1 yum三板斧&#x1f44c;查看&#x1f44c;安装&#x1f44c;卸载 &#x1f44f;1.2 拓展yum源 &#x1f44d;2. vim编辑器&#x1f90f;2.1 vim基本概念&#x1f90f;2.2 vim基本操作&#x1f90…

电路仿真软件LTspice 使用教程

一、LTspice 特点 1、免费 2、电源快速仿真 3、涵盖大量ADI产品模型 二、获取方式 LTspice信息中心 | 亚德诺半导体 如下图所示&#xff0c;根据操作系统&#xff0c;下载对应的安装包安装即可。 软件打开界面如图&#xff1a; 三、运行演示电路 一、官网下载 LTspice演…

一文读懂kubernetes部署:网关部署

部署网关 如您需要创建SSL(HTTPS)站点请先参考SSL证书的创建创建好secret 修改Ingress配置域名 首先我们要先根据域名情况更改ingress配置情况&#xff1a; 非SSL站点 vi/opt/kubernetes/gateway/ingress.yaml SSL站点 创建secret kubectl-nns-javashopcreatesecrettlsxxx-se…

Caffeine本地缓存

1、Caffine简介 简单说&#xff0c;Caffine 是一款高性能的本地缓存组件 由下面三幅图可见&#xff1a;不管在并发读、并发写还是并发读写的场景下&#xff0c;Caffeine 的性能都大幅领先于其他本地开源缓存组件 2、常见的缓存淘汰算法 2.1、FIFO 它是优先淘汰掉最先缓存的数据…

SQL优化的方法

&#xff08;1&#xff09;建立物化视图或尽可能减少多表查询。 &#xff08;2&#xff09;以不相干子查询替代相干子查询。 &#xff08;3&#xff09;只检索需要的列。 &#xff08;4&#xff09;用带in的条件子句等价替换or子句。 &#xff08;5&#xff09;经常提交com…

如何科学地利用MTTR优化软件交付流程?

谷歌提出的衡量 DevOps 质量的 DORA 指标让 MTTR&#xff08;平均恢复时间&#xff09; 名声大振。在本文中&#xff0c;你将了解到 MTTR 的作用、为什么它对行业研究很有用、你可能被它误导的原因以及如何避免 MTTR 产生的弊端。 MTTR 究竟是在测量什么&#xff1f; MTTR …

【服务器】springboot服务端接口公网远程调试 - 实现HTTP服务监听

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

chatgpt赋能python:Python中如何删除:最全面的教程

Python中如何删除&#xff1a;最全面的教程 在Python编程中&#xff0c;许多情况下需要对数据进行操作&#xff0c;其中一种最基本的操作之一是删除。本文章将是一个关于Python中如何删除的最全面的教程。我们将会介绍Python中删除的概念、各种删除方法、删除前后的注意事项以…

同元自主可控半实物仿真从方案到实践

千寻万觅待花开 在日益激烈的市场竞争环境下&#xff0c;新产品的开发和面世遇到更高的要求和挑战&#xff0c;市场对其可靠性和稳定性的要求也日益提高。完全基于软件仿真的开发过程只实现了系统结构及原理、算法的验证&#xff0c;最终样机硬件系统并未进行仿真测试或者进行仿…

一寸照片的尺寸是多少?证件照尺寸如何修改?

一寸证件照是我们日常生活中非常常用的证件照。无论是办理身份证、驾驶证、护照还是其他证件&#xff0c;都需要提供一寸证件照。一寸证件照是指照片尺寸为2.5cm3.5cm的照片&#xff0c;通常要求符合一定的标准。但是大家在需要使用一寸证件照时&#xff0c;发现自己的证件照尺…

基于微信小程序制作一个记账小工具

你不理财,财不理你,制作一个记账小程序对自己的收入/支出明细进行管理,守护好自己的钱袋子。 一、小程序1.1 项目创建1.2 首页1.3 收支报表页1.4 记账提交页1.5 记账列表页

Transformer升级之路:一种全局长度外推的新思路

©PaperWeekly 原创 作者 | 苏剑林 单位 | 追一科技 研究方向 | NLP、神经网络 说到 Transformer 无法处理超长序列的原因&#xff0c;大家的第一反应通常都是 Self Attention 的二次复杂度。但事实上&#xff0c;即便忽略算力限制&#xff0c;常规的 Transformer 也无法处…

NetApp ONTAP Select 混合云存储解决方案

NetApp ONTAP Select 集敏捷性与经验证的数据管理功能于一体。 为什么选择 ONTAP Select 来实施混合云&#xff1f; -强大而敏捷的存储 既具备 ONTAP 软件的强大功能&#xff0c;也能够灵活地部署在远程办公室/后台位置以及数据中心外部的专用边缘环境中的商用硬件上。ONTAP …

python---逻辑运算符

and 并且 一假则假 or 或者 一真则真 not 逻辑取反 下面举例介绍上面代码的运行情况 运行结果如下: EG: 针对上述情况可以简化代码成如下: 短路操作 左侧为false右侧不在求值

如何使用 Megatron-LM 训练语言模型

在 PyTorch 中训练大语言模型不仅仅是写一个训练循环这么简单。我们通常需要将模型分布在多个设备上&#xff0c;并使用许多优化技术以实现稳定高效的训练。Hugging Face &#x1f917; Accelerate 的创建是为了支持跨 GPU 和 TPU 的分布式训练&#xff0c;并使其能够非常容易的…

WPS 借助 ML Kit 无缝翻译 43 种语言,每年净省 6,500 万美元

△ 动画说明: 在笔记本电脑屏幕中&#xff0c;汉字 "文" 将变为字母 "A"&#xff0c;代表文本的横线将逐一出现&#xff0c;就像有人在输入内容一样。 WPS 是一款办公套件软件&#xff0c;可让用户轻松查看和编辑其所有文档、演示文稿、电子表格等。作为一…

JetBrains的Go语言集成开发环境GoLand 2023版本在Win10系统的下载与安装配置教程

目录 前言一、GoLand 安装二、使用配置总结 前言 GoLand是一款专为Go语言开发人员设计的集成开发环境&#xff08;IDE&#xff09;。它提供了丰富的功能和工具&#xff0c;可以帮助开发人员更高效地编写、调试和部署Go应用程序。 GoLand的主要特点&#xff1a; ——代码编辑…

Learning C++ No.25【开散列封装unordered_set和unordered_map】

引言&#xff1a; 北京时间&#xff1a;2023/5/29/7:05&#xff0c;上星期更文一篇&#xff0c;且该篇博客在周三就写完了&#xff0c;所以充分体现&#xff0c;咱这个星期摆烂充分&#xff0c;哈哈哈&#xff01;现在的内心情感没有以前那么从容了&#xff0c;这次摆的时间是…

MySQL高级篇复盘笔记(二)【日志、主从复制、分库分表、读写分离】

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…