CMake 项目切换 Ninja 构建问题排查记录

CMake 项目切换 Ninja 构建问题排查记录

1. 背景

在 CMake 项目编译时,原先经常需要手动使用:

bash 复制代码
make -j

来启用并行编译。后来希望通过配置 CMakePresets.json,改用 Ninja 构建系统,从而避免每次手动指定 make -j

需要注意的是,这里应当是 Ninja ,不是 Jinja

  • Ninja:C/C++ 项目常用的构建工具,CMake 可以生成 Ninja 构建文件。
  • Jinja:Python 模板引擎,和 CMake 并行构建无直接关系。

2. 目标

希望通过 CMakePresets.json 固定使用 Ninja:

json 复制代码
{
    "version": 8,
    "configurePresets": [
        {
            "name": "x64",
            "displayName": "GCC 13.3.0 x86_64-linux-gnu",
            "description": "正在使用编译器: C = /usr/bin/gcc, CXX = /usr/bin/g++",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "generator": "Ninja",
            "cacheVariables": {
                "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
                "CMAKE_C_COMPILER": "/usr/bin/gcc",
                "CMAKE_CXX_COMPILER": "/usr/bin/g++",
                "CMAKE_BUILD_TYPE": "Debug",
                "FETCHCONTENT_BASE_DIR": "${sourceDir}/.deps"
            }
        }
    ]
}

核心配置是:

json 复制代码
"generator": "Ninja"

这样 CMake 会生成 Ninja 构建文件,而不是 Unix Makefiles。


3. 出现的问题

配置项目时报错:

text 复制代码
CMake Error: Error: generator : Ninja
Does not match the generator used previously: Unix Makefiles
Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.

同时日志中还出现:

text 复制代码
CMake Error at /usr/share/cmake-4.2/Modules/FetchContent.cmake:1916 (message):
  CMake step for libhv failed: 1

这说明不仅主项目可能存在旧缓存,FetchContent 下载和构建的依赖项目也可能存在旧缓存。


4. 根因分析

CMake 的构建目录中会保存生成器信息。

如果某个目录之前用:

text 复制代码
Unix Makefiles

配置过,之后又在同一个目录里改成:

text 复制代码
Ninja

CMake 会拒绝继续配置,因为同一个构建目录不能混用不同 generator。

本次问题的关键点在于:

json 复制代码
"FETCHCONTENT_BASE_DIR": "${sourceDir}/.deps"

项目把 FetchContent 的依赖缓存目录指定到了:

bash 复制代码
.deps

因此,虽然主构建目录可能已经清理过,但 .deps 里面的 libhv 子项目构建缓存仍然记录着旧的:

text 复制代码
Unix Makefiles

当主项目切换到 Ninja 后,FetchContent 重新配置 libhv 时就发生 generator 冲突。


5. 最终解决方法

删除 .deps 后重新生成即可:

bash 复制代码
rm -rf .deps
cmake --preset x64

如果希望彻底清理,也可以同时删除主构建目录:

bash 复制代码
rm -rf out/build/x64
rm -rf .deps
cmake --preset x64

然后编译:

bash 复制代码
cmake --build out/build/x64

如果配置了 buildPresets,则可以使用:

bash 复制代码
cmake --build --preset x64

6. 推荐补充 buildPresets

原来的配置只包含 configurePresets,这是可以正常使用的。

但为了让命令更统一,推荐补充 buildPresets

json 复制代码
{
    "version": 8,
    "configurePresets": [
        {
            "name": "x64",
            "displayName": "GCC 13.3.0 x86_64-linux-gnu",
            "description": "正在使用编译器: C = /usr/bin/gcc, CXX = /usr/bin/g++",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "generator": "Ninja",
            "cacheVariables": {
                "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
                "CMAKE_C_COMPILER": "/usr/bin/gcc",
                "CMAKE_CXX_COMPILER": "/usr/bin/g++",
                "CMAKE_BUILD_TYPE": "Debug",
                "FETCHCONTENT_BASE_DIR": "${sourceDir}/.deps"
            }
        }
    ],
    "buildPresets": [
        {
            "name": "x64",
            "configurePreset": "x64"
        }
    ]
}

这样后续构建流程可以统一为:

bash 复制代码
cmake --preset x64
cmake --build --preset x64

7. 是否还需要 make -j

如果使用的是:

json 复制代码
"generator": "Ninja"

通常不需要再手动写:

bash 复制代码
make -j

因为 Ninja 默认会自动并行构建。

如果仍然使用默认的 Unix Makefiles,则通常需要:

bash 复制代码
cmake --build build -j

或者:

bash 复制代码
make -j$(nproc)

也可以使用 CMake 的通用并行参数:

bash 复制代码
cmake --build build --parallel

或者设置环境变量:

bash 复制代码
export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc)

8. 后续排查建议

以后遇到类似错误:

text 复制代码
Does not match the generator used previously

优先检查并清理以下目录:

bash 复制代码
rm -rf out/build/x64
rm -rf .deps

如果明确只是 FetchContent 子项目出问题,通常只清理:

bash 复制代码
rm -rf .deps

即可。


9. 本次结论

本次问题不是 CMakePresets.json 配置错误,而是 .deps 中的 FetchContent 子项目缓存仍然保留了旧的 Unix Makefiles generator 信息。

删除 .deps 后,CMake 重新下载并配置依赖,所有子项目都统一使用 Ninja,问题解决。

最终推荐使用:

bash 复制代码
cmake --preset x64
cmake --build --preset x64

并在项目中固定:

json 复制代码
"generator": "Ninja"

这样后续不需要再手动执行 make -j

10. 致谢

致谢土区GPT5.5 : )

相关推荐
汉克老师5 小时前
GESP2025年6月认证C++五级( 第一部分选择题(1-8))
c++·链表·线性筛·最大公约数·gesp5级·gesp五级·埃氏筛
tjl521314_215 小时前
03C++ 定位 new 运算符(Placement new)
开发语言·c++
乐观勇敢坚强的老彭5 小时前
c++信奥循环嵌套讲解
开发语言·c++
十五年专注C++开发5 小时前
Qt实现带多选功能的组合复选框
开发语言·c++·qt·qcombobox
郭源潮16 小时前
从8k嘈杂到16k清晰,我是如何使用RNNoise+libresample构建音频降噪管道的?
c++·音视频·实时音视频
@小码农6 小时前
2026年信息素养大赛【星火征途】图形化编程复赛和决赛模拟题B
开发语言·数据结构·c++·算法
tjl521314_216 小时前
02C++ 静态变量与链接性
java·jvm·c++
(Charon)6 小时前
【C++/Qt】Qt 实现 WebSocket 测试工具:连接、消息收发与通信日志
c++·qt·websocket
Hello eveybody6 小时前
学习C++的好处
开发语言·c++