直接fork vcpkg或Conan不现实,因其非工具库而是完整构建系统:vcpkg依赖PowerShell/Shell脚本与端口DSL,Conan依赖Python运行时、client/server架构及profile机制;轻量级替代方案需绕开运行时与中心化服务,聚焦本地策略控制与构建劫持。

为什么直接 fork vcpkg 或 Conan 不现实
因为它们不是“工具库”,而是完整构建系统:vcpkg 重度依赖 PowerShell/Shell 脚本 + 自定义端口(port)DSL,Conan 依赖 Python 运行时 + server/client 架构 + profile 机制。想从零实现一个轻量级、可嵌入 C++ 项目的自动拉取+缓存+编译工具,核心得绕开运行时依赖和中心化服务——重点在本地策略控制和构建过程劫持。
vcpkg install 背后真正发生什么
它本质是三步原子操作:① 解析 ports/xxx/portfile.cmake 获取源码地址、patch 列表、CMake 参数;② 下载到 downloads/ 并解压到 buildtrees/;③ 用 cmake --build 编译进 packages/。你不需要复刻整个 portfile 体系,但必须自己定义等价的元数据格式(比如 JSON),并严格分离下载、解压、配置、构建四个阶段。
- 缓存路径必须可配置,且默认不写入用户家目录(避免权限问题),建议设为
./.deps_cache - 下载失败必须带重试 + 断点续传(
libcurl的CURLOPT_RESUME_FROM可用,但更稳妥是删残文件后重下) - 解压不能直接
system("tar -xf"),要用libarchive或minizip,否则 Windows 上 zip 路径分隔符(\vs/)会出错 - 编译命令必须显式指定
-DCMAKE_INSTALL_PREFIX,否则头文件和库会散落各处,后续find_package()找不到
怎么让 CMake 自动发现你编译好的库
关键不是改 CMakeLists.txt,而是生成标准的 xxxConfig.cmake 文件。vcpkg 做法是模板生成(scripts/buildsystems/vcpkg.cmake 注入逻辑),Conan 是运行时写 conanbuildinfo.cmake。你只需在构建完成后,用 C++ 拼一个最简版:
set(<code>XXX_VERSION</code> "1.2.3")
set(<code>XXX_INCLUDE_DIRS</code> "${CMAKE_CURRENT_LIST_DIR}/../include")
set(<code>XXX_LIBRARIES</code> "${CMAKE_CURRENT_LIST_DIR}/../lib/libxxx.a")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(XXX REQUIRED_VARS XXX_INCLUDE_DIRS XXX_LIBRARIES)
然后把这文件放进 .deps_cache/packages/xxx/1.2.3/lib/cmake/xxx/,并在主项目中加 set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/.deps_cache/packages/xxx/1.2.3") 即可。
立即学习“C++免费学习笔记(深入)”;
Windows 上 msbuild 和 ninja 的兼容陷阱
同一份 CMake 配置,在 Ninja 下能跑,在 MSVC 工具链下可能链接失败——根本原因是 find_library() 在 Windows 默认只搜 .lib,但某些开源库(如 OpenSSL)只提供 .dll.a(MinGW 风格)。解决办法只有一个:在生成 xxxConfig.cmake 时,根据实际产出的库名动态写死 XXX_LIBRARIES,而不是依赖 find_library()。
- 不要信任
find_package(OpenSSL)—— 它可能找到系统旧版本,必须强制走你缓存的路径 - MSVC 编译的静态库(
.lib)和动态导入库(.lib)同名,但内容不同,必须通过dumpbin /headers xxx.lib确认是否含IMPORT字样 - Ninja 默认并发数太高,某些库(如 ICU)编译会因头文件竞争失败,需加
--jobs=2
真正的难点不在下载或编译,而在于让下游 CMake 项目完全无感地切换到你的缓存路径——这要求每个库的 Config.cmake 必须精准匹配其实际布局,且不能假设任何全局环境变量存在。


















