You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:25:18