C++20模块能否不构建库使用?CMake报错解析与修复
C++标准模块在CMake直接添加到可执行目标时的错误解析与修复
代码示例
main.cxx
import foo; int main() { foo f; f.helloworld(); return 0; }
foo.cxx
module; #include <iostream> export module foo; export class foo { public: foo() = default; ~foo() = default; void helloworld(); }; void foo::helloworld() { std::cout << "hello world\n"; }
可正常构建的CMake配置(库目标方式)
cmake_minimum_required(VERSION 3.28) project(std_module_example CXX) set(CMAKE_CXX_STANDARD 20) add_library(foo) # 将模块文件添加到库目标 target_sources(foo PUBLIC FILE_SET CXX_MODULES FILES foo.cxx ) add_executable(hello main.cxx) target_link_libraries(hello foo)
报错的CMake配置(直接添加到可执行目标)
cmake_minimum_required(VERSION 3.28) project(std_module_example CXX) set(CMAKE_CXX_STANDARD 20) add_executable(hello main.cxx foo.cxx)
错误信息
bin> CXX=clang++ CC=clang cmake -GNinja .. -- The CXX compiler identification is Clang 18.1.3 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/clang++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done (0.6s) -- Generating done (0.0s) -- Build files have been written to: /home/pietrom/Documents/dev/test/modules/bin bin> ninja -v [1/6] "/usr/bin/clang-scan-deps-18" -format=p1689 -- /usr/bin/clang++ -std=c++20 -x c++ /home/pietrom/Documents/dev/test/modules/main.cxx -c -o CMakeFiles/hello.dir/main.cxx.o -MT CMakeFiles/hello.dir/main.cxx.o.ddi -MD -MF CMakeFiles/hello.dir/main.cxx.o.ddi.d > CMakeFiles/hello.dir/main.cxx.o.ddi.tmp && mv CMakeFiles/hello.dir/main.cxx.o.ddi.tmp CMakeFiles/hello.dir/main.cxx.o.ddi [2/6] "/usr/bin/clang-scan-deps-18" -format=p1689 -- /usr/bin/clang++ -std=c++20 -x c++ /home/pietrom/Documents/dev/test/modules/foo.cxx -c -o CMakeFiles/hello.dir/foo.cxx.o -MT CMakeFiles/hello.dir/foo.cxx.o.ddi -MD -MF CMakeFiles/hello.dir/foo.cxx.o.ddi.d > CMakeFiles/hello.dir/foo.cxx.o.ddi.tmp && mv CMakeFiles/hello.dir/foo.cxx.o.ddi.tmp CMakeFiles/hello.dir/foo.cxx.o.ddi [3/6] /usr/bin/cmake -E cmake_ninja_dyndep --tdi=CMakeFiles/hello.dir/CXXDependInfo.json --lang=CXX --modmapfmt=clang --dd=CMakeFiles/hello.dir/CXX.dd @CMakeFiles/hello.dir/CXX.dd.rsp FAILED: CMakeFiles/hello.dir/CXX.dd /home/pietrom/Documents/dev/test/modules/bin/CMakeFiles/hello.dir/CXXModules.json CMakeFiles/hello.dir/main.cxx.o.modmap CMakeFiles/hello.dir/foo.cxx.o.modmap /usr/bin/cmake -E cmake_ninja_dyndep --tdi=CMakeFiles/hello.dir/CXXDependInfo.json --lang=CXX --modmapfmt=clang --dd=CMakeFiles/hello.dir/CXX.dd @CMakeFiles/hello.dir/CXX.dd.rsp CMake Error: Output CMakeFiles/hello.dir/foo.cxx.o provides the `foo` module but it is not found in a `FILE_SET` of type `CXX_MODULES` ninja: build stopped: subcommand failed.
错误含义解析
这条错误的核心是:CMake识别到foo.cxx编译后生成的目标文件提供了foo标准模块,但该模块源文件没有被正确归类到CXX_MODULES类型的FILE_SET中。
CMake 3.28对C++20标准模块的构建有严格规则:所有定义模块的源文件必须通过FILE_SET CXX_MODULES的方式声明,不能像普通源文件一样直接添加到add_executable或add_library的参数中。直接添加会导致CMake无法识别这是模块源文件,进而无法正确处理模块依赖、编译顺序和模块映射等逻辑。
修复方法
针对可执行目标,同样需要使用FILE_SET CXX_MODULES来声明模块源文件,修改后的CMake配置如下:
cmake_minimum_required(VERSION 3.28) project(std_module_example CXX) set(CMAKE_CXX_STANDARD 20) add_executable(hello main.cxx) # 将模块源文件添加到可执行目标的CXX_MODULES文件集 target_sources(hello PUBLIC FILE_SET CXX_MODULES FILES foo.cxx )
原理说明
- 通过
target_sources配合FILE_SET CXX_MODULES,明确告诉CMakefoo.cxx是C++标准模块的定义文件,CMake会自动处理模块的编译依赖、生成模块接口文件,并确保main.cxx在编译时能正确找到foo模块。 - 这种方式和库目标的处理逻辑一致,符合CMake对C++模块的规范要求。
内容的提问来源于stack exchange,提问作者Pietro
相关产品推荐
相关产品推荐

