与编译器编译输出大小相关的某些因素
问题背景
在编译一个极其简单的 C++
入门示例( test.cpp
)的时候,发现 Code::Blocks
编译的结果比 Visual Studio
编译的结果大许多。
研究过程
我们使用如下工具,对 test.cpp
文件进行编译测试,探究与编译器编译输出大小相关的因素。
测试环境
Code::Blocks 17.12
与GCC 5.1.0
Visual Studio 2017
与MSVC++ 15.0
GCC 8.1.0
1 | //test.cpp |
问题重现
一般来说,不同的 IDE
都有不同的默认编译选项。我们先用命令行复原模拟 Code::Blocks 17.12
和 Visual Studio 2017
的编译过程。
1 | // Code::Blocks 17.12 |
输出大小为 1528KB
。对于如此简单的代码,这个大小可以说相当大了。
VS
的编译过程较为复杂,我们不再用命令行模拟,但 VS
的编译输出大小只用 193KB
。
问题定位
问题可以重现,也就代表这个问题背后有较为稳定的原因,多半是代码造成的结果,而不是玄学导致的,我们也就不用玄学排错了。由于很难用命令行模拟VS编译,我们下面就主要使用 GCC 5.1.0
进行测试。
很容易想到是不是静态链接和动态链接的原因,我们先用 -static
编译选项看一下静态链接编译输出的大小。
1 | // GCC 5.1.0 |
输出大小为 1528KB
,和之前完全一样。为什么静态链接会和动态链接的编译输出一样大?我们查看 GCC
的安装目录,我们可以看到它压根就没有动态库,全部是 .a
静态链接库文件。
至此可以说仅就这个问题来说算是找到答案了。 Code::Blocks
下载时配套的编译器为GCC 5.1.0
,而该编译器没有携带动态库,只支持静态链接(也就是说不管添不添加-static
编译选项,都是静态链接)。相反,VS
下载时一并下载了Windows SDK
,里面包含了 C Runtime Library
(C运行时库),而且既有静态运行时库,也有动态运行时库,因此 Visual Studio
支持静态链接和动态链接, Visual Studio
使用动态链接编译的结果显然比Code::Blocks
使用静态链接 编译的结果小许多。
我们用携带动态链接库的 GCC 8.1.0
编译该文件,得到的输出结果大小只有56KB
,甚至比 VS
的还要小(当然通过修改编译选项, VS
的输出结果也能做到这么小,甚至更小,毕竟GCC
开源, VS
有微软的技术支撑,而且 GCC
本来就不是 Windows
平台的原生编译器,对 Windows
的支持一定没有微软自家好)。
拓展研究
Release
和 Debug
我们比较Release
和 Dubug
两个版本的编译输出。
1 | // GCC 8.1.0 |
Debug
版有 75KB
, Release
版有 56KB
。对于我们的测试代码差别不大,但大型项目的 Release
和 Debug
版本大小就会相差悬殊。
编译器的版本
不同的编译器或者同一编译器的不同版本生成的编译输出大小可能就不同。
1 | // GCC 8.1.0 |
生成的编译输出大小为2552KB
,比GCC 5.1.0
还要大。猜测可能是因为要支持更新的C++ 20
标准,链接了更多的文件。
IDE
和编译器添加的其它优化
总结
与编译器编译输出大小相关的因素一般有如下几个原因
- 编译器的链接选项不同,静态链接比动态链接更小(支持动态链接的前提是你要有动态库,不然编译选项是不管用的)。
- 编译器可以生成
Release
版和Debug
版,后者包含调试信息,一般来说体积更大。 - 编译器不同,更新版本的编译器生成的代码可能
更小更小或更大。 IDE
和编译器添加了其他的优化选项。