整理:【CMake】换台机器就编译失败?用 Presets + vcpkg 固定依赖、工具链与 CI(学习笔记)

今天翻到一篇不错的技术分享,看完之后自己也琢磨了一下,把思路梳理记录下来。

🔥个人主页:爱和冰阔乐 📚专栏传送门:《数据结构与算法》 、C++ 🐶学习方向:C++方向学习爱好者 ⭐人生格言:得知坦然 ,失之淡然

🏠博主简介

文章目录

五、用 CMake Presets 固定构建入口 六、toolchain 路径放在哪里 七、Ninja 和 Visual Studio 别用同一套配置思路 八、二进制缓存解决重复编译九、本地、IDE 与 CI 使用同一套命令十、换台机器失败时怎么查 十一、发布前的验收清单 总结参考资料

前言

C++ 项目里经常会遇到一种很难受的问题:

开发者 A 的 Windows 能编译
开发者 B 的 Linux 找不到依赖
IDE 里能运行,命令行却不行
本地 Debug 正常,CI Release 失败
重新拉取仓库后装到了另一套依赖
换一台机器,CMake 参数全靠聊天记录恢复

许多时候,问题并不在某一条编译命令,而是构建输入没有被完整保存

一套构建至少要回答下面这些问题:

使用哪个生成器?
使用哪个编译器和工具链?
构建类型是什么?
打开了哪些项目选项?
依赖从哪里解析,版本基线是什么?
源码目录和构建目录在哪里?
测试命令怎样执行?
本地、IDE 和 CI 是否使用同一套参数?

如果答案散落在 IDE 设置、环境变量、个人脚本和口头约定里,CMakeLists.txt 写得再整齐,换台机器依然可能失败。

这篇文章用一个小型 C++ 项目,把 CMakePresets.jsonCMakeUserPresets.json 和 vcpkg manifest 串起来。重点不是“怎么安装 CMake”,而是怎样把容易漂移的参数和依赖,从个人机器搬进一套可检查、可版本管理的构建入口。


一、先弄清楚:到底要复现什么

严格的位级可复现,会继续涉及时间戳、归档顺序、绝对路径映射和链接器行为。普通项目先把目标放在“构建过程可复现”上:

同一份源码
同一套声明的工具链与依赖
同一套构建选项
在支持的平台上得到功能一致的结果

构建输入大致可以分成四层:

层级典型内容建议放置位置项目结构target、源码、链接关系CMakeLists.txt项目依赖fmt、Catch2、nlohmann-jsonvcpkg.json共享构建方法生成器、构建目录、选项、测试入口CMakePresets.json个人机器信息本机 vcpkg 路径、私有 SDKCMakeUserPresets.json 或环境变量

核心: CMakeLists.txt 描述“项目是什么”,Preset 描述“这次准备怎样构建”,User Preset 只补充“当前机器有什么不同”。

把个人绝对路径写进共享 Preset,会让仓库只在作者机器上可用;把所有参数都塞进个人文件,又会让团队无法复现。分层并不是为了多维护几个文件,而是把“项目事实”和“本机事实”分开。


二、准备一个最小项目

目录如下:

reproducible-cpp/
├── CMakeLists.txt
├── CMakePresets.json
├── CMakeUserPresets.example.json
├── vcpkg.json
├── src/
│   ├── main.cpp
│   ├── checksum.cpp
│   └── checksum.hpp
└── tests/
    └── checksum_test.cpp

src/checksum.hpp

#pragma once

#include

namespace demo {

unsigned long long checksum(std::string_view text);

}

src/checksum.cpp

#include "checksum.hpp"

namespace demo {

unsigned long long checksum(std::string_view text)
{
    unsigned long long value = 1469598103934665603ULL;

    for (unsigned char character : text)
    {
        value ^= character;
        value *= 1099511628211ULL;
    }

    return value;
}

}

src/main.cpp

```

include


include

include

include

include "checksum.hpp"

int main(int argc, char** argv)
{
const std::string input =
argc > 1 ? argv[1] : "hello";

nlohmann::json result{
{"input", input},
{"checksum", demo::checksum(input)}
};

std::cout


暂时整理到这里。以上都是个人理解,可能有疏漏,欢迎指正。

评论 (0)

暂无评论