我已经阅读了几篇关于 C++ 20 新功能“modules”的文章,并尝试在我的新项目中使用它们。但我不清楚的是我是否应该在编译器选项中禁用预编译头?
根据我的理解,我的源代码(模块实现文件)中包含的所有标头都进入全局模块范围并仅编译一次,因此不再使用预编译标头。
就我而言,我正在编写一个 Windows DLL,它高度依赖于 windows.h 头文件。这是相当大的头文件,它不是 C++ 20 模块接口文件,只是普通的头文件。
我的模块实现文件看起来像这样:
// ModuleA.cpp
module;
#include <windows.h>
module ModuleA;
void Initialize() {
// Some code..
}
我的项目中有很多这样的*.cpp文件。
此外,我还在我的 *.ixx(模块接口)文件中包含 windows.h 标头,因为没有这个标头,他们对 DWORD、SHORT、UINT、APIENTRY 一无所知 类型。当然,我可以使用 unsigned long 代替 DWORD 和 __stdcall 代替 APIENTRY 等,但这对我来说不太方便。
我担心,如果我在 Visual Studio 2022 C++ 编译器选项中禁用预编译头选项,windows.h 文件将被编译多次。
由于我在这里没有得到任何答案,所以我决定测试 C++ 20 模块与经典代码编译速度。 我创建了 20 个 C++ 项目中的 4 个:
每个项目都包含 500 个头文件和 500 个经典代码项目的源文件。 以及 500 个模块接口文件 (.ixx) 和 500 个模块实现文件 (.cpp),用于基于 Modern C++ 20 模块的项目。 所有源文件和模块实现文件都有
#include "framework.h"
表示非预编译头文件版本,#include "pch.h"
表示启用了预编译头文件的版本。
“framework.h” 文件包含以下标头:
// framework.h
#pragma once
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
结果如下:
// █ Classic code, no Precompiled Header █
1>All 510 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>NoModules-NoPCH.vcxproj -> \x64\Release\NoModules-NoPCH.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 22:05:55 and took 03:50.216 minutes ==========
Build output folder size: 659 MB (691 732 507 bytes)
// █ Classic code with Precompiled Header █
1>All 510 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>NoModules-PCH.vcxproj -> \x64\Release\NoModules-PCH.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 22:06:39 and took 04.573 seconds ==========
Build output folder size: 90.9 MB (95 344 891 bytes)
// █ Modern C++ 20 code (Modules), no Precompiled Header █
1>All 515 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>Modules-Cpp20.vcxproj -> \x64\Release\Modules-Cpp20.exe
1>Done building project "Modules-Cpp20.vcxproj".
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 22:12:03 and took 04:30.789 minutes ==========
Build output folder size: 1.47 GB (1 586 401 470 bytes)
// █ Modern C++ 20 code (Modules) with Precompiled Header █
1>All 510 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>Modules-Cpp20-PCH.vcxproj -> \x64\Release\Modules-Cpp20-PCH.exe
1>Done building project "Modules-Cpp20-PCH.vcxproj".
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 22:13:10 and took 19.306 seconds ==========
Build output folder size: 249 MB (261 284 309 bytes)
到目前为止,最快编译是启用预编译头的经典C++代码,花费了04.573秒。创建的 *.obj 类文件:90.9 MB(95 344 891 字节)。
而最慢是带模块的现代C++ 20代码,但没有预编译头文件,花费了04:30.789分钟。还创建了很多 *.obj 之类的 1.47 GB(1 586 401 470 字节)的东西。
我将测试项目上传到 GitHub:cpp20-compiler-tests。 我不认为这些测试不是最好的,现实世界的项目可能会表现出不同的性能。我不知道。
但我相信它回答了我的问题:
我是否应该将预编译头与 C++ 20 模块一起使用?并且它表明答案是
YES。 它表明 C++ 20 全局模块片段无法取代预编译头文件,至少在今天是这样。也许有一天,谁知道呢...