运行时库链接方式实践指南(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.mzph.cn/pingmian/34889.shtml

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

相关文章

新手教学系列——“笑看”单元测试(pytest)

探索单元测试的必要性 你是否曾经思考过,当前的业务场景是否真的需要单元测试?我们每个人负责的模块是否也需要单元测试?什么阻碍了我们进行单元测试呢?时间紧,任务重,还要写测试?这些都是我们在开发过程中常见的问题。假设我们有一个计划开发一周的项目,让我们看看有…

[Redis]事务

Redis事务 Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。 但是,事务中的每条命令都会与 Redis 服务器进行网络交互,比较浪费资源 所以,日常开发中不建议使…

工控 UI 风格美轮美奂

工控 UI 风格美轮美奂

出现apimswincrtruntimel110dll丢失不兼容的情况如何快速修复?

在使用多种软件应用的过程中,我们时常面对一些技术难题,其中动态链接库(DLL)文件的兼容性问题尤为常见。这些问题不仅可能干扰应用程序的平稳运行,还有可能危及整个操作系统的稳定。例如,“api-ms-win-crt-…

九、(正点原子)Linux定时器

一、Linux中断简介 1、中断号 每个中断都有一个中断号,通过中断号即可区分不同的中断,有的资料也把中断号叫做中断线。在 Linux 内核中使用一个 int 变量表示中断号。在Linux中,我们可以使用已经编写好的API函数来申请中断号,定义…

一个土木工程专业背景的开发者,讲述开源带给他的力量

在前段时间我们举办的“TDengine Open Day”第一季技术沙龙中,TDengine 应用研发高级工程师谭雪峰进行的“开源之路:程序员的成长与探索”主题分享获得了众多参会者的好评。谭雪峰从自身独特的职业发展经历出发,分享了自己在开源领域的种种收…

B端系统:增删改查中的新建(增)页面如何设计体验更爽。

在B系统中,增删改查是最基本、最常用的功能之一。这四个操作对于系统的正常运行和数据管理至关重要。其中,新增(新建)页面的设计尤为关键,因为它直接影响着用户体验和系统功能的完整性。 一、新增(新建&…

项目实训-vue(十七)

项目实训-vue(十七) 文章目录 项目实训-vue(十七)1.概述2.问诊类型3.问诊时间统计4.看诊时间统计 1.概述 本篇博客将记录我在数据统计页面中的工作。因为项目并未实际运行,因此我们拟定了一些数据,并构建了…

DIY 智能门禁:用 ESP32 RFID 打造安全便捷的家居体验 (附代码)

一、系统概述 本项目旨在使用 ESP32 微控制器和 RFID 技术构建一个安全可靠的门禁系统。该系统利用 RFID 卡进行身份验证,通过读取卡内存储的唯一 ID,判断用户权限并控制门锁的开关。ESP32 强大的 Wi-Fi 功能还能实现远程监控和管理,方便用户…

【SHAP解释运用】基于python的树模型特征选择+随机森林回归预测+SHAP解释预测

1.导入必要的库 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.tree import export…

Stable Diffusion 3 文本生成图像 在线体验 原理分析

前言 本文分享使用Stable Diffusion 3实现文本生成图像,可以通过在线网页中免费使用的,也有API等方式访问。 同时结合论文和开源代码进行分析,理解其原理。 Stable Diffusion 3是Stability AI开发的最新、最先进的文本生成图像模型&#x…

性能工具之 MySQL OLTP Sysbench BenchMark 测试示例

文章目录 一、前言二、测试环境1、服务器配置2、测试拓扑 三、测试工具安装四、测试步骤1、导入数据2、压测数据3、清理数据 五、结果解析六、最后 一、前言 做为一名性能工程师掌握对 MySQL 的性能测试是非常必要的,本文基于 Sysbench 对MySQL OLTP(联…

现在的Java面试都这么扯淡了吗?

在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「java的资料从专业入门到高级教程」, 点个关注在评论区回复“666”之后私信回复“666”,全部无偿共享给大家!!!开发兼过半年面试官 刚开始…

网络安全等级保护测评

网络安全等级保护 《GB17859 计算机信息系统安全保护等级划分准则》 规定计算机信息系统安全保护等级共分五级 《中华人民共和国网络安全法》 “国家实行网络安全等级保护制度。 等级测评 测评机构依据国家网络安全等级保护制度规定,按照有关 管理规范和…

JVM虚拟机的组成

一、为什么要学习 JVM ? 1. “ ⾯试造⽕箭,⼯作拧螺丝” , JVM 属于⾯试官特别喜欢提问的知识点; 2. 未来在⼯作场景中,也许你会遇到以下场景: 线上系统突然宕机,系统⽆法访问,甚⾄直…

2024年虚拟现实、图像和信号处理国际学术会议(ICVISP 2024,8月2日-4)

2024年虚拟现实、图像和信号处理国际学术会议(ICVISP 2024)将于2024年8月2-4日在中国厦门召开。ICVISP 2024将围绕“虚拟现实、图像和信号处理”的最新研究领域, 为来自国内外高等院校、科学研究所、企事业单位的专家、教授、学者、工程师等提…

迁移方案详解|使用YMP从异构数据库迁移到YashanDB

数据迁移简介 01典型场景与需求 在国产化浪潮下,数据库系统的国产化替代成为了一个日益重要的议题,有助于企业降低对外依赖,提升信息安全和自主性。 以Oracle、MySQL为代表的传统关系型数据库管理系统,在企业应用中占据了重要的…

图书馆借阅表

DDL 用户表 (Users) 图书表 (Books) 图书类别表 (BookCategories) 图书与类别关联表 (BookCategoryRelations) 借阅记录表 (BorrowRecords) 供应商表 (Suppliers) 采购记录表 (PurchaseRecords) CREATE TABLE Users (user_id INT PRIMARY KEY AUTO_INCREMENT,username …

pytorch神经网络训练(VGG-19)

VGG-19 导包 import torchimport torch.nn as nnimport torch.optim as optimimport torchvisionfrom torchvision import datasets, transformsfrom torch.utils.data import DataLoaderimport matplotlib.pyplot as plt 数据预处理和增强 transform transforms.Compose(…

在 Go 中如何让结构体不可比较?

最近我在使用 Go 官方出品的结构化日志包 slog 时,看到 slog.Value 源码中有一个比较好玩的小 Tips,可以限制两个结构体之间的相等性比较,本文就来跟大家分享下。 在 Go 中结构体可以比较吗? 在 Go 中结构体可以比较吗&#xff…