VS开发 - 静态编译和动态编译的基础实践与混用

目录

[1. 基础概念](#1. 基础概念)

[2. 直观感受一下静态编译和动态编译的体积与依赖项目](#2. 直观感受一下静态编译和动态编译的体积与依赖项目)

[3. VS运行时库包含哪些主要文件(从VS2015起)](#3. VS运行时库包含哪些主要文件(从VS2015起))

[4. 动态库和静态库混用的情况](#4. 动态库和静态库混用的情况)

[5. 感谢清单](#5. 感谢清单)


1. 基础概念

所谓的运行时库(Runtime Library)就是WINDOWS系统给我们实现了C/C++的库函数的功能,提供的.LIB和.DLL文件。

其中.LIB是静态库,假如我们程序用.LIB去链接的话,意味着这个EXE里就包含了C/C++库函数的实现,运行的时候就不需要再依赖目标电脑上的运行库,方便拿到其他电脑跑。缺点呢,就是程序体积大。

.DLL则是动态库,选择动态链接的时候,EXE需要用到C/C++库函数的实现的时候,会去系统里面找相对应的DLL。多个程序也可以共享这一个DLL,带来的好处就是节省EXE的体积,但是拿到其他电脑去的话可能跑不起来,报错说:"找不到XXXXX.DLL"

我们用visual studio开发的时候,在项目属性里面可以看到有4种运行时库可选

|-------|------|---------|
| 运行库名称 | 链接方式 | 其他 |
| MT | 静态 | |
| MTd | 静态 | Debug版本 |
| MD | 动态 | |
| MDd | 动态 | Debug版本 |

2. 直观感受一下静态编译和动态编译的体积与依赖项目

用vs新建一个工程,简单写一个hello world的程序。

cpp 复制代码
#include <iostream>
using namespace std;

int main()
{
	cout << "Hello World" << endl;
	return 0;
}

然后分别用静态生成和动态生成:

由上面两个图片可以清晰地看出来:静态编译体积大,动态编译依赖多

3. VS运行时库包含哪些主要文件(从VS2015起)

|------------|----------------------|-----------------------|----------------------------------------------|------------------------------------------------|
| 库描述 | MT | MTD | MD | MDd |
| 通用C运行时库 | libucrt.lib | libucrtd.lib | ucrt.lib ucrtbase.dll | ucrtd.lib ucrtbased.dll |
| VC运行库 | libvcruntime.lib | libvcruntimed.lib | vcruntime.lib vcruntime<version>.dll | vcruntimed.lib vcruntime<version>d.dll |
| C++标准库 | libcpmt.lib | libcpmtd.lib | msvcprt.lib msvcp<version>.dll | msvcprtd.lib msvcp<version>d.dll |
| 初始化CRT的代码库 | libcmt.lib | libcmtd.lib | msvcrt.lib | msvcrtd.lib |

参考链接:C 运行时 (CRT) 和 C++ 标准库 (STL) .lib 文件 | Microsoft Learn

仔细留意一下【初始化CRT的代码库】,为什么动态生成的依赖库只有lib++没有dll++,官网说它的dll就是【通用C运行时库】和【VC运行库】的合集。这里有点难理解,也不知道为什么要这么设计呢?希望前辈们多多指教一下。

4. 动态库和静态库混用的情况

假如我们现在EXE使用动态编译,但依赖一个静态编译而成的LIB,可以吗?

试试!首先自己编译一个lib。头文件如下:

cpp 复制代码
#pragma once

void StaticHello(); // 定义一个函数

源文件如下:

cpp 复制代码
#include "my_mtd_lib.h"
#include <iostream>
using namespace std;

// 实现头文件的函数
void StaticHello()
{
	cout << "----------" << endl;
}

生成选项用调试版的的静态库MTd

接着在其他工程调用这个LIB

cpp 复制代码
#include <iostream>
using namespace std;

#include "../my-mtd-lib/my_mtd_lib.h"
#pragma comment(lib, "../Debug/my-mtd-lib.lib")

int main()
{
	cout << "**********" << endl;
	StaticHello(); // 调用my-mtd-lib.lib的函数
	return 0;
}

生成选项用调试版的动态库MDd

点生成报错:

cpp 复制代码
1>libcpmtd.lib(wlocale.obj) : error LNK2005: "public: int __thiscall std::ios_base::flags(void)const " (?flags@ios_base@std@@QBEHXZ) 已经在 msvcprtd.lib(MSVCP140D.dll) 中定义
1>libcpmtd.lib(wlocale.obj) : error LNK2005: "public: __int64 __thiscall std::ios_base::width(__int64)" (?width@ios_base@std@@QAE_J_J@Z) 已经在 msvcprtd.lib(MSVCP140D.dll) 中定义
1>libcpmtd.lib(wlocale.obj) : error LNK2005: "public: __int64 __thiscall std::ios_base::width(void)const " (?width@ios_base@std@@QBE_JXZ) 已经在 msvcprtd.lib(MSVCP140D.dll) 中定义
1>libcpmtd.lib(xlocale.obj) : error LNK2005: "public: int __thiscall std::ios_base::flags(void)const " (?flags@ios_base@std@@QBEHXZ) 已经在 msvcprtd.lib(MSVCP140D.dll) 中定义
1>libcpmtd.lib(xlocale.obj) : error LNK2005: "public: int __thiscall std::basic_streambuf<char,struct std::char_traits<char> >::sputc(char)" (?sputc@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QAEHD@Z) 已经在 msvcprtd.lib(MSVCP140D.dll) 中定义
1>libcpmtd.lib(xlocale.obj) : error LNK2005: "public: __int64 __thiscall std::ios_base::width(__int64)" (?width@ios_base@std@@QAE_J_J@Z) 已经在 msvcprtd.lib(MSVCP140D.dll) 中定义
1>libcpmtd.lib(xlocale.obj) : error LNK2005: "public: __int64 __thiscall std::ios_base::width(void)const " (?width@ios_base@std@@QBE_JXZ) 已经在 msvcprtd.lib(MSVCP140D.dll) 中定义

报的都是同一个错:libcpmtd.libmsvcprtd.lib冲突,有符号重定义。再仔细看是不是很眼熟,刚好是前面 ++第三部分++ 表格里面【C++标准库】里面MTd和MDd,跟我们项目的设定一一对应。我对这个报错的理解是:链接阶段,main.obj会找到msvcprtd.lib里面关于cout的符号,也发现my-mtd-lib.lib也带了来自libcpmtd.lib的cout的符号,所以报重定义。

所以一个项目里面像我的例子这样混用两个运行时库,实际上大概率不行,理论上也不好。最优的做法当然是所有依赖都基于同一套运行时库。

5. 感谢清单

这篇文章是受到下面博主的文章指引启发的,感谢前辈的分享

你所不知道的C和C++运行库_vcc++运行库-CSDN博客

相关推荐
Prejudices4 分钟前
C++如何调用Python脚本
开发语言·c++·python
单音GG7 分钟前
推荐一个基于协程的C++(lua)游戏服务器
服务器·c++·游戏·lua
qing_04060323 分钟前
C++——多态
开发语言·c++·多态
孙同学_23 分钟前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
charlie1145141911 小时前
Qt Event事件系统小探2
c++·qt·拖放·事件系统
iiiiiankor1 小时前
C/C++内存管理 | new的机制 | 重载自己的operator new
java·c语言·c++
小辛学西嘎嘎1 小时前
C/C++精品项目之图床共享云存储(3):网络缓冲区类和main
c语言·开发语言·c++
无敌最俊朗@1 小时前
stm32学习之路——八种GPIO口工作模式
c语言·stm32·单片机·学习
c语言鹌鹑蛋1 小时前
C++初阶 --- 类和对象(1)
开发语言·c++
Jack黄从零学c++2 小时前
opencv(c++)图像的灰度转换
c++·人工智能·opencv