第92章:使用vcpkg:集成vcpkg包管理器
做C++开发的朋友应该都有过这种经历:项目里要用个第三方库,比如OpenSSL、Boost、CURL这些,手动下载、编译、配置路径,折腾半天。更头疼的是换台机器或者换个人接手,这套流程又得重来一遍。嗯,我当年刚入行时就吃过这个亏——项目里用了七八个库,光写FindXXX.cmake就写了一周,后来同事接手直接崩溃。
vcpkg就是来解决这个痛点的。它是微软开源的一个C++包管理器,说白了就是帮你自动下载、编译、安装第三方库的工具。你只需要告诉它"我要用这个库",剩下的它全包了。
92.1 vcpkg是什么?
vcpkg是一个跨平台的C++包管理器。它支持Windows、Linux、macOS,也支持各种编译器和架构。我个人习惯把它理解成"C++界的pip"——虽然不完全一样,但思路是相通的。
它的核心工作流程很简单:
- 从GitHub或上游仓库拉取库的源码
- 根据当前平台和编译器配置编译参数
- 编译成静态库或动态库
- 安装到指定目录
- 生成CMake集成文件,让find_package能找到它
你看,整个过程完全自动化。我在项目中遇到过最典型的场景:新同事入职,拉完代码后只需要执行vcpkg install,所有依赖就齐活了。再也不用写那种又臭又长的"环境搭建文档"了。
92.2 安装vcpkg
安装vcpkg其实就两步,没什么复杂的:
# 克隆仓库
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
# 运行引导脚本
# Windows:
./bootstrap-vcpkg.bat
# Linux/macOS:
./bootstrap-vcpkg.sh
引导完成后,你会得到一个vcpkg可执行文件。我建议把它加到PATH里,这样全局都能用。当然,你也可以直接用相对路径调用。
C:\dev\vcpkg或者~/tools/vcpkg这种固定的位置。这样不管开多少个项目,都共用同一个vcpkg实例,省磁盘空间。
92.3 安装库的基本操作
安装一个库,命令非常简单:
# 搜索可用库
vcpkg search fmt
# 安装库(默认x64)
vcpkg install fmt
# 安装指定架构
vcpkg install fmt:x86-windows
vcpkg install fmt:arm64-linux
# 查看已安装的库
vcpkg list
这里有个细节要注意:vcpkg默认安装的是x64版本的库。如果你需要32位或者ARM版本,得显式指定triplet(就是冒号后面那串)。
为什么会这样?因为vcpkg的设计理念是"显式优于隐式"。它不想替你做决定,万一猜错了你的目标平台,编译出来的库不能用,那才叫坑。
92.4 在CMake中集成vcpkg
这才是本章的重点。vcpkg装好了库,怎么让CMake找到它们?
有两种方式:
方式一:通过工具链文件
这是最推荐的方式。vcpkg会生成一个CMake工具链文件,你只需要在CMake配置时指定它:
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake
然后在CMakeLists.txt里,你就可以直接用find_package了:
cmake_minimum_required(VERSION 3.14)
project(MyApp)
# 注意:不需要手动设置CMAKE_PREFIX_PATH
# vcpkg的工具链文件会自动处理
find_package(fmt CONFIG REQUIRED)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt)
你看,代码干净多了。不需要写一堆set(CMAKE_PREFIX_PATH ...),也不用担心路径写死的问题。
find_package能找到对应的Config文件就行。
方式二:通过CMAKE_PREFIX_PATH
如果你不想用工具链文件,也可以手动设置路径:
cmake -B build -S . \
-DCMAKE_PREFIX_PATH=[vcpkg-root]/installed/x64-windows/share
但我不推荐这么做。原因很简单——你手动指定的路径是硬编码的,换台机器就得改。而工具链文件是vcpkg自带的,只要vcpkg的位置不变,它就永远有效。
92.5 实战:一个完整的例子
我们来写一个完整的例子,用vcpkg管理fmt库和nlohmann/json库。
首先,安装依赖:
vcpkg install fmt nlohmann-json
然后,项目结构如下:
myapp/
├── CMakeLists.txt
├── main.cpp
└── vcpkg.json (可选,用于清单模式)
CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(JsonLogger)
# 使用C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找vcpkg安装的库
find_package(fmt CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
add_executable(json_logger main.cpp)
target_link_libraries(json_logger PRIVATE
fmt::fmt
nlohmann_json::nlohmann_json
)
main.cpp:
#include <fmt/core.h>
#include <nlohmann/json.hpp>
#include <iostream>
int main() {
nlohmann::json config;
config["name"] = "vcpkg demo";
config["version"] = 1.0;
fmt::print("Config: {}\n", config.dump(4));
return 0;
}
配置和编译:
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build build
./build/json_logger
输出结果:
Config: {
"name": "vcpkg demo",
"version": 1.0
}
整个过程一气呵成。你想想看,如果没有vcpkg,你得手动下载fmt和nlohmann-json的源码,编译,然后配置CMake路径。现在只需要两行命令加几行CMake代码就搞定了。
92.6 清单模式(Manifest Mode)
vcpkg还支持清单模式。说白了就是在项目根目录放一个vcpkg.json文件,里面声明项目依赖。这样别人拉代码后,只需要执行vcpkg install,所有依赖自动装好。
vcpkg.json示例:
{
"name": "myapp",
"version": "1.0.0",
"dependencies": [
"fmt",
"nlohmann-json",
"spdlog"
]
}
然后在CMake里启用清单模式:
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake \
-DVCPKG_MANIFEST_MODE=ON
我个人非常推荐这种做法。它把依赖管理做到了项目级别,而不是机器级别。每个项目都有自己的依赖清单,互不干扰。
vcpkg.json和手动vcpkg install,可能会产生冲突。建议二选一:要么纯清单模式,要么纯手动模式。我曾经在项目里混用过,结果vcpkg报了"端口冲突"的错误,排查了半天才发现是两种模式打架了。
92.7 知识体系图
下面这张图展示了vcpkg与CMake集成的完整流程:
92.8 常见问题与避坑
用vcpkg的过程中,有几个坑我踩过,分享给你:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| find_package找不到库 | 没有指定工具链文件,或者路径不对 | 检查CMAKE_TOOLCHAIN_FILE是否指向正确的vcpkg.cmake |
| 编译报错:找不到头文件 | 库没有安装,或者安装的是不同架构 | 运行vcpkg list确认库已安装,且triplet匹配 |
| 链接错误:未定义的符号 | 库的编译选项与项目不一致 | 检查VCPKG_TARGET_TRIPLET是否设置正确 |
| vcpkg install很慢 | 从GitHub下载源码,国内网络不稳定 | 配置镜像源,或者使用--binarysource=clear跳过二进制缓存 |
--binarysource=default参数,vcpkg会优先使用预编译的二进制包,速度能快10倍。
92.9 总结
vcpkg和CMake的集成,说白了就是三步:
- 用vcpkg安装你需要的库
- 在CMake配置时指定vcpkg的工具链文件
- 在CMakeLists.txt里直接用find_package
就这么简单。但它的价值在于——你不再需要手动管理第三方库的下载、编译、路径配置。所有依赖都通过vcpkg统一管理,项目可移植性大大提升。
我个人建议,新项目从一开始就用vcpkg + 清单模式。虽然前期多花几分钟配置,但后续维护省下的时间,绝对值得。
公众号:蓝海资料掘金营,微信deep3321