CMake环境下C++模块中std::string_view的异常行为问询
环境信息
- MSVC 14.37.32822
- 编译器版本19.37.32825
问题现象
相同的C++模块代码,在纯Visual Studio项目中无需在main.ixx里包含<string_view>就能编译通过,但在CMake构建环境下,必须在main.ixx中手动添加#include <string_view>才能编译,否则会出现编译错误。
代码示例
Logger.ixx
module; #include <iostream> #include <format> #include <string_view> export module Logger; export template<typename... Args> void Log(std::string_view format, Args&&... args) { auto result = std::vformat(format, std::make_format_args(args...)); std::cout << result << std::endl; }
main.ixx(CMake环境下必须包含<string_view>)
import Logger; // CMake环境下编译成功必须包含此行,纯VS项目无需 #include <string_view> int main() { Log("Hello {}", "world"); return 0; }
未包含<string_view>时的编译错误
====================[ Build | VulkanEngine | Debug-Visual Studio ]============== "C:\Program Files\JetBrains\CLion 2023.2.2\bin\cmake\win\x64\bin\cmake.exe" --build C:\Dev\VulkanEngine\cmake-build-debug-visual-studio --target VulkanEngine --config Debug CMake is re-running because C:/Dev/VulkanEngine/cmake-build-debug-visual-studio/CMakeFiles/generate.stamp is out-of-date. the file 'C:/Dev/VulkanEngine/CMakeLists.txt' is newer than 'C:/Dev/VulkanEngine/cmake-build-debug-visual-studio/CMakeFiles/generate.stamp.depend' result='-1' -- Configuring done (0.0s) -- Generating done (0.0s) -- Build files have been written to: C:/Dev/VulkanEngine/cmake-build-debug-visual-studio MSBuild version 17.7.2+d6990bcfa for .NET Framework Scanning sources for module dependencies... main.ixx Logger.ixx Compiling... Logger.ixx main.ixx C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\system_error(221,39): error C3774: cannot find 'std::partial_ordering': Please include <compare> header [C:\Dev\VulkanEngine\cmake-build-debug-visual-studio\VulkanEngine.vcxproj] C:\Dev\VulkanEngine\main.ixx(5,5): message : see reference to function template instantiation 'void Log<const char(&)[6]>(std::string_view,const char (&)[6])' being compiled [C:\Dev\VulkanEngine\cmake-build-debug-visual-studio\VulkanEngine.vcxproj] C:\Dev\VulkanEngine\Logger.ixx(13,10): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'std::string' (or there is no acceptable conversion) [C:\Dev\VulkanEngine\cmake-build-debug-visual-studio\VulkanEngine.vcxproj] ...(后续错误信息省略)
核心问题
为什么纯Visual Studio项目与CMake构建环境会出现这种差异?
原因分析
VS默认预编译头的隐性支持
纯Visual Studio新建项目时默认启用预编译头(比如pch.h),里面已经包含了<string_view>、<compare>、<string>等常用标准库头文件。即便main.ixx不手动包含这些头文件,预编译头也已经导入了必要的声明,自然不会报错。CMake对模块依赖的严格遵循
CMake处理MSVC的C模块时,严格遵循C标准规则:模块全局片段(module;后的#include部分)里的头文件属于模块私有依赖,不会被导出到模块接口中。Logger模块里的<string_view>是私有依赖,不会传递给导入它的main.ixx,因此main.ixx必须自行包含才能获取类型声明。模板实例化的上下文要求
在main.ixx中调用Log模板函数时,编译器需要当前上下文存在std::string_view的完整定义,以及std::string的operator<<重载(因为std::vformat返回std::string,要输出到cout)。CMake环境下没有预编译头的隐性支持,也没有模块传递的依赖,这些声明缺失就会导致编译错误。
内容的提问来源于stack exchange,提问作者TheAlphaKarp

