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 : )

相关推荐
小小编程路16 小时前
C++ 多线程与并发
java·jvm·c++
程序leo源17 小时前
Qt窗口详解
开发语言·数据库·c++·qt·青少年编程·c#
zh_xuan18 小时前
解决VS Code 控制台中文乱码
c++·vscode·乱码
郭涤生18 小时前
飞凌 RK3588 开发板同显 / 异显模式切换
c++·rk3588
计算机安禾18 小时前
【c++面向对象编程】第38篇:设计原则(二):里氏替换、接口隔离与依赖倒置
开发语言·c++
code_whiter19 小时前
C++1进阶(继承)
开发语言·c++
智者知已应修善业19 小时前
【51单片机LED闪烁10次数码管显示0-9】2023-12-14
c++·经验分享·笔记·算法·51单片机
智者知已应修善业19 小时前
【51单片机2按键控制1个敞亮LED灯闪烁和熄灭】2023-11-3
c++·经验分享·笔记·算法·51单片机
咩咦20 小时前
C++学习笔记20:日期类比较运算符重载
c++·学习笔记·类和对象·运算符重载·比较运算符·日期类
paeamecium20 小时前
【PAT甲级真题】- A+B in Hogwarts
c++·算法·pat考试·pat