运行时库链接方式实践指南(MT、MD、MTd、MDd)

前言

笔者曾经编译一个库提供给使用者,提供库后发现由于运行时库连接方式不一致,导致使用者无法连接笔者提供的库。另一方面,理解和选择正确的运行时链接方式对于构建高效、可靠的应用程序至关重要。
因此,本文将展开运行时库的基本概念、讨论不同的运行时链接类型,以及如何根据项目需求选择最合适的链接方式。

什么是运行时?

运行时库(Runtime Library):这是一组标准化的软件函数集合,提供程序运行时所需的基本服务,比如I/O处理、内存管理等。例如标准模板库、C函数库等。

运行时库链接方式

运行时链接方式关主要分为两大类:静态链接和动态链接。

静态链接

静态链接是在编译时期将所有必要的库函数代码直接打包到最终的可执行文件中。静态链接产生的可执行文件通常体积较大,但它们不依赖外部的库文件,提高了应用的独立性和便于部署。

动态链接

与静态链接相对,动态链接是在运行时期加载所需的运行时库(通常是动态链接库DLL或共享对象SO)。动态链接的应用程序体积较小,可以实现库文件的共享使用,节省系统资源。

如何选择链接方式

选择链接方式时,需要综合考虑多个因素:

  • 部署简易性:如果需要简化部署过程,不希望处理外部的运行时库依赖,静态链接是一个不错的选择。

  • 体积和资源占用:如果对可执行文件的体积和内存占用有严格要求,动态链接可以减少重复的库代码占用。

  • 更新和维护:动态链接便于库文件的更新和维护,特别是当涉及到安全更新和修复时。

  • 兼容性:在有些环境中,动态链接更受欢迎,因为它保证了与系统的兼容性和一致性。

  • 特殊需求:对于需要插件或按需加载功能的应用,运行时动态链接或延迟加载等技术可能更合适。

MSVC实战

MSVC(Microsoft Visual C++)的编译选项MT、MD、MTd、MDd指定了程序是静态链接到运行时库还是动态链接,以及是否是调试版本的库。

以下是每个选项的含义:

  • MT:将程序与多线程版的静态运行时库进行链接。
  • MD:将程序与多线程版的动态运行时库(DLL)进行链接。
  • MTd:将程序与多线程版的静态运行时库进行链接,并且是调试版。
  • MDd:将程序与多线程版的动态运行时库(DLL)进行链接,并且是调试版。

MT 和 MD 分别代表:MT: Multi-Threaded和MD: Multi-Threaded DLL。早期的 Microsoft Visual C++ 版本中,存在单线程版本的运行时库,这些运行时库不支持多线程程序,从 Visual Studio 2005 开始,所有的运行时库都是多线程的(MT 或 MD),单线程的运行时库已经被淘汰。

优缺点

  • MT/MTd(静态链接)的优点是不需要在部署时包含额外的运行时库DLL文件,因为所有的运行时代码都已经包含在最终的可执行文件中。这简化了部署过程并减少了对环境的依赖。缺点是最终的可执行文件会比较大(因为把运行时库二进制也带进来了),如果项目中多个库使用了静态链接运行时库,也会出现重复的、冗余的代码占用内存。
  • MD/MDd(动态链接)的优点是可执行文件体积较小,多个程序可以共享同一份运行时库的副本,节省资源。缺点是在部署程序时需要确保正确版本的运行时库DLL文件也被安装在目标系统上,否则程序无法运行。

如果使用动态链接,但是没有打包运行时库会怎样?

许多开发者都可能遇到忘记打包运行时库的场景,表现上是在自己电脑上正常运行,但是发布到其他电脑上提示找不到xxx.dll,例如:
在这里插入图片描述
网上也提供了很多接近方案,例如VC Runtime 集合,包含了各种版本的 Visual C++ 运行时库的集合。如果一个应用程序是使用特定版本的 Visual Studio 编译的,并且使用了动态链接库(DLL),那么它就需要相应版本的 VC Runtime 来确保正确运行。

VC Runtime 集合的出现主要是为了解决以下问题:

  1. 版本兼容:不同的应用程序可能需要不同版本的 VC Runtime。一个集合包含了多个版本的运行时库,可以确保大多数应用程序的兼容性。

  2. 简化安装:用户可以一次性安装多个版本的 VC Runtime,而不需要单独下载和安装每个应用程序需要的特定版本。

  3. 解决缺失:如果用户遇到因为缺少 VC Runtime 导致的问题,安装集合包可以快速解决缺失的库文件问题。

从某种角度上来说,VC Runtime 集合的存在并不直接代表软件开发者没有正确打包动态运行时库,而是因为操作系统或软件的多样性和复杂性,使得拥有一个集合包来解决潜在的兼容性问题变得更加方便和必要。不过,为了减少不必要的用户反馈,最佳实践仍然是我们在软件分发时包括所有必要的依赖,确保自己的软件不出现运行时库的缺少的问题。

其他编译器的情况

在Clang和GCC上的对应选项:它们都支持静态链接和动态链接的概念,但是Clang和GCC在选择运行时库时和MSVC的选项不一样。

  • 在GCC中,你可以使用-static选项来静态链接到库。GCC默认动态链接到glibc。
  • 在Clang中,链接方式的选择也可以通过指定链接器(linker)参数来实现,比如使用-static进行静态链接。

在Linux上,通常默认链接到系统的动态运行时库,因此不需要特别指定。如果需要静态链接,可能需要确保静态版本的运行时库已经安装,并在链接时指定对应的选项。

在使用静态链接时,需要确保遵守所有依赖库的许可协议,因为静态链接可能会将代码合并到可执行文件中。

在编译大型项目中的实践

大型项目,例如QtFramework,在配置时一般都有编译选项支持选择如何链接运行时库,以满足开发者自定义编译的需求。
翻阅Qt源码,可以找到这个选项:
在这里插入图片描述
通过config help也能找到:
在这里插入图片描述
QT默认的编译选项是-MD,当这个选项开启时,会将-MD替换为-MT。
在这里插入图片描述

其他的开源项目也是类似,基本都会有参数可以让开发者自定义选择运行库链接方式,因为如果在库中使用库,那么链接方式必须一样才能被正确链接。

为什么在同一个项目中,库的运行时库的链接方式必须一样

在同一个项目中,所有组件使用相同的运行时库链接方式是非常重要的,主要原因是确保一致性、稳定性和避免潜在的冲突。具体来说:

1. 对象内存管理

不同的运行时库可能有不同的内存管理机制。如果一个对象在一个运行时库中被创建(分配内存),而在另一个运行时库中被销毁(释放内存),可能会导致内存泄漏或者更糟糕的情况。确保所有库使用相同的运行时库可以防止这种情况发生。

2. 全局状态的一致性

静态链接的运行时库将其全局状态编译进每个可执行文件或库中。如果一个项目中混用了静态和动态链接的运行时库,可能导致有多个独立的全局状态实例存在于同一个进程中,这会导致异常行为,比如不一致的全局变量状态、初始化和终止序列混乱等。

3. C++异常处理

在C++中,如果不同的组件使用了不同的运行时库,可能会导致异常处理不兼容。例如,一个用MDd编译的DLL抛出的异常可能无法被用MTd编译的可执行文件正确捕获或处理。

4. 类型定义和实现

运行时库通常包含了标准类型和函数的实现。如果不同的运行时库版本被混合使用,可能会导致类型定义上的冲突或者不同的实现之间的不兼容,导致运行时错误。

5. 线程和同步对象

多线程编程通常依赖于运行时库提供的同步机制,如互斥锁和条件变量。如果混用不同的运行时库,线程同步对象的行为可能会不一致,导致死锁或竞争条件。

6. 依赖和链接问题

如果项目中的不同部分链接了不同的运行时库,可能会出现难以诊断的链接错误,因为链接器可能无法解析多个版本的符号和库。

为了确保软件稳定运行,维护性和可预测性,需要在同一个项目中使用相同的运行时库链接方式。如果必须混用不同的链接方式,往往会有编译器链接报错。

结语

在软件开发中,了解不同运行时的特点并实际应用它们,或者编译出正确的库提供给使用方,是每个软件工程师技能库中不可或缺的一部分。
通过本文系统性的介绍,相信你对运行时库的概念、特点。一致性的重要性有了更深的认识。
如果想要了解如何确定在软件分发时(安装包)需要打包哪些运行时库文件,请参考:《深入解析VC Runtime:什么是vcruntimeXXX.dll和api-ms-win-crt-runtime-X-X-X.dll?》

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

运算放大器(运放)输入偏置电流、失调电流

输入偏置电流定义 理想情况下,并无电流进入运算放大器的输入端。而实际操作中,始终存在两个输入偏置电流,即IB和IB-(参见图1)。 I B I_B IB​的值大小不一,在静电计AD549中低至60 fA(每三微秒通过一个电子),而在某些高…

go~缓存设计配合singleFlight

一个缓存设计,配合go的singleFlight 最开始的设计如下 添加分布式缓存 上线后分布式缓存上涨的流量并不等于下游下降的流量,而是下游下降的流量 * 2~3 究其原因,就是采用了go的singleFlight,假定请求缓存时长10ms&a…

仿真CAN报文发送的CRC校验算法(附CAPL代码)

文章目录 前言一、为什么CAN报文有CRC?二、怎么确定是否需要做CRC校验?三、CAPL代码实现CRC算法 前言 关于CRC校验的基本理论、算法实现网上已经有很多介绍文章,本文不再赘述。只是记录在项目测试中真正开发CRC算法并进行测试的一些体会。 …

Geoserver源码解读四 REST服务

文章目录 文章目录 一、概要 二、前置知识点-FreeMarker 三、前置知识点-AbstractHttpMessageConverter 3.1 描述 3.2 应用 四、前置知识点-AbstractDecorator 4.1描述 4.2 应用 五、工作空间查询解读 5.1 模板解读 5.2 请求转换器解读 一、概要 关于geoserver的r…

ASUS/华硕幻14 2023 GA402X系列 原厂Windows11-22H2系统

安装后恢复到您开箱的体验界面,带原机所有驱动和软件,包括myasus mcafee office 奥创等。 最适合您电脑的系统,经厂家手调试最佳状态,性能与功耗直接拉满,体验最原汁原味的系统。 原厂系统下载网址:http:…

激光与相机融合标定汇总:提升融合算法的精度与可靠性(附github地址)

前言 随着科技的飞速发展,激光技术与相机技术的融合已成为推动智能化影像发展的重要力量。这种融合不仅提高了成像的精度和效率,还为相关行业带来了革命性的变革。在这篇博客中,我们将深入探讨激光与相机融合标定的原理及其在各个领域的应用…

@ComponentScan注解在Spring的作用

ComponentScan注解的作用是什么? 告知Spring扫描那些包下的类,可以配置includeFilters,excludeFilters,过滤某些类,更多内容可以具体看下此注解文件。 Spring是如何通过这个注解将类注入到Ioc容器中的? 请…

【数字基础设施1007】探索数字基础设施的影响:宽带政策变量数据集来了!

今天给大家分享的是国内顶级期刊2023年发表论文《数字基础设施与代际收入向上流动性——基于“宽带中国”战略的准自然实验》使用到的重要数据集——“宽带中国”政策变量数据、互联网发展指数以及工具变量(所在城市到杭州市的球面距离和到“八纵八横”政策节点城市…

加密与安全_Java 加密体系 (JCA) 和 常用的开源密码库

文章目录 Java Cryptography Architecture (JCA)开源国密库国密算法对称加密(DES/AES⇒SM4)非对称加密(RSA/ECC⇒SM2)散列(摘要/哈希)算法(MD5/SHA⇒SM3) 在线生成公钥私钥对,RSA公私钥生成参考…

Docker Compose 入门

想象一下在服务器上运行静态页面的场景。对于这项任务,NGINX 服务器是一个不错的选择。我们在 static-site/index.html 路径下有一个简单的 HTML 文件: 通过使用 Docker,我们将使用以下官方镜像运行 NGINX 服务器 docker run --rm -p 8080:…

spring boot jar 启动报错 Zip64 archives are not supported

spring boot jar 启动报错 Zip64 archives are not supported 原因、解决方案问题为什么 spring boot 不支持 zip64zip、zip64 功能上的区别zip 的文件格式spring-boot-loader 是如何判断是否是 zip64 的? 参考 spring boot 版本是 2.1.8.RELEASE,引入以…

Hi3861 OpenHarmony嵌入式应用入门--中断按键

本篇讲解gpio的中断使用方式。 硬件原理图如下,与上一篇一样的电路 GPIO API API名称 说明 hi_u32 hi_gpio_init(hi_void); GPIO模块初始化 hi_u32 hi_io_set_pull(hi_io_name id, hi_io_pull val); 设置某个IO上下拉功能。 hi_u32 hi_gpio_set_dir(hi_gpio_…

汽车零部件制造企业如何选择合适的ESOP电子作业指导书系统

随着汽车产业的不断发展,汽车零部件制造企业在提高生产效率和产品质量方面面临着越来越大的挑战。为了解决这些问题,越来越多的汽车零部件制造企业开始采用ESOP电子作业指导书系统,以帮助他们管理和优化生产流程。但是,在选择合适…

three.js - MeshPhongMaterial材质(实现玻璃水晶球效果)

1、概念 phong网格材质:Mesh - Phong - Material 一种用于具有镜面高光的光泽表面的材质。 它可以模拟,具有镜面高光的光泽表面,提供镜面反射效果。 MeshPhongMaterial: MeshPhongMaterial是一种基于Phong光照模型的材质&#…

FreeRTOS信号量和互斥量

信息量 简介 信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。 前面介绍的队列(queue)可以用于传输数据:在任务之间、任务和中断之间。 消息队列用于传输多个数据,但是有时候我们只需要传递状态,这个状态值需要用…

招聘,短信与您:招聘人员完整指南

招聘人员面临的最大挑战之一就是沟通和联系候选人。为何?我们可以从以下原因开始:候选人通常被太多的招聘人员包围,试图联系他们,这使得你很难吸引他们的注意。在招聘过程的不同阶段,根据不同的工作量,让申请人保持最…

8.12 矢量图层面要素单一符号使用七(随机标记填充)

文章目录 前言随机标记填充(Random Marker Fill)QGis设置面符号为随机标记填充(Random Marker Fill)二次开发代码实现随机标记填充(Random Marker Fill) 总结 前言 本章介绍矢量图层线要素单一符号中使用随…

Swift 6:导入语句上的访问级别

文章目录 前言示例启用 AccessLevelOnImport破坏性变更采用这些更改总结前言 SE-0409 提案引入了一项新功能,即允许使用 Swift 的任何可用访问级别标记导入声明,以限制导入的符号可以在哪些类型或接口中使用。由于这些变化,现在可以将依赖项标记为对当前源文件(private 或…

element-plus 日期选择添加确定按钮

需求&#xff1a;选择日期后&#xff0c;点击确定按钮关闭面板 思路&#xff1a; 使用shortcuts自定义确定和取消按钮选择日期后使用handleOpen()强制开启面板点击确定后使用handleClose()关闭面板 <template><el-date-pickerref"pickerRef"v-model"…

龙国南方航空滑块acw_v2+cookie+风控处理+type后缀

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未经许可禁…