C++20模块分区编译失败求助(Linux+Clang16+CMake3.26)
环境
Linux、Clang 16.0.6、CMake 3.26.x
我参考一篇C模块文章成功编译运行了简单示例,但尝试C20模块分区时编译失败:
代码文件
main.cpp
#include <iostream> import mod1; //import mod1:b; auto main() -> int{ std::cout << G2::tell_me_more() << std::endl; }
mod1.ixx
module; #include <string> export module mod1; export namespace G1 { auto tell_me () -> std::string { return "OK for me"; } }
mod1b.ixx
module; #include <string> export module mod1:b; export namespace G2 { auto tell_me_more () -> std::string { G1::tell_me(); // <- 错误位置 return "OK for me 2"; } }
编译错误
error: use of undeclared identifier 'G1'
CMake配置
... set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a") set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) include(modules.cmake) add_module_library(mod1b src/mod1b.ixx ) add_module_library(mod1 src/mod1.ixx ) add_executable(${APP_NAME} main.cpp) set_target_properties(${APP_NAME} PROPERTIES LINKER_LANGUAGE CXX) target_link_libraries(${APP_NAME} mod1 mod1b) ...
我原本以为C++模块可以不需要单独的头文件和实现文件,但现在似乎需要声明G1的接口。请问有没有无需额外接口文件的解决方法?
编辑1:
发现mod1b的编译早于mod1(手动简化路径):
Generating mod1b.pcm [build] FAILED: mod1b.pcm path/mod1b.pcm [build] cd build_path && /usr/bin/clang++-16 -std=c++20 -x c++-module --precompile -c -o mod1b.pcm /my_path/src/mod1b.ixx
编辑2:
根据建议调整代码后仍报错:
mod1-b.ixx
module; #include <string> export module mod1:b; export namespace G2 { auto tell_me_more () -> std::string { return "OK for me 2"; } }
mod1.ixx
module; #include <string> export module mod1; import :b; // 此处报错,即使使用"export import :b"也不行 export namespace G1 { auto tell_me () -> std::string { G2::tell_me_more(); // 忽略返回值,此处不关心 return "OK for me"; } }
main.cpp
#include <iostream> import mod1; auto main() -> int{ std::cout << G1::tell_me() << std::endl; }
新错误:
fatal error: module 'mod1:b' not found
解决方法
核心问题
- 模块分区的归属关系:C++20的模块分区(如
mod1:b)是主模块mod1的一部分,不能作为独立模块处理。你把主模块和分区拆成两个add_module_library目标,CMake无法识别它们属于同一个模块,导致编译顺序混乱、模块找不到的问题。 - 分区依赖规则:分区之间默认不能直接访问彼此内容,需要通过主模块导入或显式声明依赖。循环导入主模块和分区会直接触发编译错误。
具体修复步骤
1. 调整代码,理顺依赖
如果分区mod1:b需要访问主模块的G1,同时要让主模块使用者能访问G2,修改如下:
- mod1b.ixx:导入主模块以访问
G1
module; #include <string> export module mod1:b; // 导入主模块mod1,获取G1的接口 import mod1; export namespace G2 { auto tell_me_more () -> std::string { G1::tell_me(); return "OK for me 2"; } }
- mod1.ixx:导出分区
mod1:b,让main.cpp导入mod1后能访问G2
module; #include <string> export module mod1; // 导出分区b,将其接口合并到主模块中 export import :b; export namespace G1 { auto tell_me () -> std::string { return "OK for me"; } }
2. 修复CMake配置
将主模块和分区放在同一个模块库目标中,让CMake识别它们属于同一个模块,自动处理编译顺序:
... set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "2182bf5c-ef0d-489a-91da-49dbc3090d2a") set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP 1) include(modules.cmake) // 将主模块和分区文件放在同一个add_module_library中 add_module_library(mod1 src/mod1.ixx src/mod1b.ixx ) add_executable(${APP_NAME} main.cpp) set_target_properties(${APP_NAME} PROPERTIES LINKER_LANGUAGE CXX) target_link_libraries(${APP_NAME} mod1) ...
3. 处理循环依赖(若有需要)
如果主模块和分区必须互相调用,要避免直接循环导入,可提取公共接口到单独分区:
- 创建
mod1-common.ixx存放公共内容
module; #include <string> export module mod1:common; export namespace GCommon { // 公共函数/类型定义 }
- 主模块和
mod1:b都导入mod1:common,通过公共分区交互,避免直接循环依赖。
内容的提问来源于stack exchange,提问作者Kroma
相关产品推荐
相关产品推荐

