今天翻到一篇不错的技术分享,看完之后自己也琢磨了一下,把思路梳理记录下来。
🔥个人主页:爱和冰阔乐 📚专栏传送门:《数据结构与算法》 、C++ 🐶学习方向:C++方向学习爱好者 ⭐人生格言:得知坦然 ,失之淡然
🏠博主简介
文章目录
- 前言
- 一、先弄清楚:到底要复现什么
- 二、准备一个最小项目
- 三、
CMakeLists.txt只描述项目关系 - 四、用 vcpkg manifest 声明依赖和版本基线
- 4.1
vcpkg.json - 4.2
builtin-baseline固定了什么 - 4.3 feature 依赖
- 10.1 改了 Preset,却只执行 build
- 10.2 一个构建目录混多个工具链
- 10.3 IDE 和终端的环境变量不一致
- 10.4
find_package找不到已经声明的依赖 - 10.5 把所有选项继续留在命令行
前言
C++ 项目里经常会遇到一种很难受的问题:
开发者 A 的 Windows 能编译
开发者 B 的 Linux 找不到依赖
IDE 里能运行,命令行却不行
本地 Debug 正常,CI Release 失败
重新拉取仓库后装到了另一套依赖
换一台机器,CMake 参数全靠聊天记录恢复
许多时候,问题并不在某一条编译命令,而是构建输入没有被完整保存。
一套构建至少要回答下面这些问题:
使用哪个生成器?
使用哪个编译器和工具链?
构建类型是什么?
打开了哪些项目选项?
依赖从哪里解析,版本基线是什么?
源码目录和构建目录在哪里?
测试命令怎样执行?
本地、IDE 和 CI 是否使用同一套参数?
如果答案散落在 IDE 设置、环境变量、个人脚本和口头约定里,CMakeLists.txt 写得再整齐,换台机器依然可能失败。
这篇文章用一个小型 C++ 项目,把 CMakePresets.json、CMakeUserPresets.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)
暂无评论