vcpkg与CMake

vcpkg与CMake

vcpkg 和 CMake 的关系是:CMake 负责构建项目,vcpkg 负责管理依赖库,两者通过 vcpkg 提供的 CMake 工具链文件无缝集成。

简单来说,vcpkg 让"下载和安装第三方库"这件事变得简单,而 CMake 让"编译和链接这些库"变得方便。二者结合,可以极大地简化 C++ 项目的依赖管理。

核心机制:工具链文件

vcpkg 与 CMake 的集成核心在于一个 CMake 工具链文件。通过在 CMake 配置项目时指定这个文件,CMake 就能自动在 vcpkg 的安装目录中查找并使用你安装的库。

这个文件的位置是:<vcpkg-root>/scripts/buildsystems/vcpkg.cmake。

集成方法

有三种主要的方式可以将 vcpkg 集成到 CMake 项目中。

一、使用命令行指定 (最直接)

每次运行 CMake 配置命令时,通过 -DCMAKE_TOOLCHAIN_FILE 参数指定工具链文件的路径。这通常是最基础和通用的做法。

cmake 复制代码
# 在项目根目录下执行
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=<vcpkg的安装路径>/scripts/buildsystems/vcpkg.cmake

二、使用 CMakePresets.json (推荐)

现代 CMake 推荐使用 CMakePresets.json 文件来统一管理配置。你可以在项目根目录下创建此文件,并将工具链文件路径写入其中,这样团队成员无需记住复杂的命令。

json 复制代码
{
  "version": 3,
  "configurePresets": [
    {
      "name": "default",
      "cacheVariables": {
        "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
      }
    }
  ]
}

这个例子假设你设置了环境变量 VCPKG_ROOT 指向 vcpkg 的安装目录。

三、在 VS Code 中配置

第一步:安装 vcpkg 和必要工具

首先,在开始之前,确保你的电脑上已经安装了以下工具:

  1. Git:用于克隆 vcpkg 仓库。
  2. Visual Studio Code:并安装好 C/C++ (ms-vscode.cpptools) 和 CMake Tools (ms-vscode.cmake-tools) 这两个扩展。
  3. CMake:版本 3.10 或以上,并确保其在系统 PATH 中。
  4. C++ 编译器:Windows 上推荐 MSVC (需通过 VS Developer Command Prompt 启动 VS Code),Linux/macOS 上可用 GCC 或 Clang。

接下来,克隆并编译 vcpkg 本身。在终端中执行:

bash 复制代码
# 将 vcpkg 下载到本地,推荐放在一个固定的目录,如 C:/dev/
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg

# 运行引导脚本 (Windows 下运行 bootstrap-vcpkg.bat)
./bootstrap-vcpkg.sh   # Linux/macOS
.\bootstrap-vcpkg.bat  # Windows

第二步:配置 CMake 项目以识别 vcpkg

这一步是为了让 CMake 知道去哪里找 vcpkg 安装的库。我们有几种方式,推荐从 CMakePresets.json 开始。

方法一:使用 CMakePresets.json (最推荐)

在项目的根目录下创建 CMakePresets.json 文件,内容如下:

json 复制代码
{
  "version": 2,
  "configurePresets": [
    {
      "name": "vcpkg",
      "generator": "Ninja", // 或 "Visual Studio 17 2022" 等其他生成器
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
      }
    }
  ]
}

接着,再创建一个 CMakeUserPresets.json 文件 (这个文件通常不提交到 Git,适合存放本地路径):

json 复制代码
{
  "version": 2,
  "configurePresets": [
    {
      "name": "default",
      "inherits": "vcpkg",
      "environment": {
        "VCPKG_ROOT": "C:/dev/vcpkg" // 替换为你的 vcpkg 实际路径
      }
    }
  ]
}

完成之后,在 VS Code 底部状态栏点击 CMake 扩展的预设选择按钮,选中 default 预设即可。

方法二:通过 VS Code 的 settings.json 配置

如果不使用 Preset,也可以在项目根目录的 .vscode/settings.json 文件中直接指定:

json 复制代码
{
  "cmake.configureSettings": {
    "CMAKE_TOOLCHAIN_FILE": "C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake",
    "VCPKG_TARGET_TRIPLET": "x64-windows" // 根据需要设置,如 x64-windows, x64-linux 等
  }
}

第三步:管理项目的依赖库 (使用 Manifest 模式)

这是 vcpkg 的现代用法,可以确保团队成员使用相同版本的库。

  1. 初始化清单文件:在项目根目录下打开终端,运行 vcpkg new --application。这会生成一个 vcpkg.json 文件。
  2. 添加依赖:继续在终端中运行 vcpkg add port fmt 来添加一个示例库 fmt。此时 vcpkg.json 文件的内容会变成:
json 复制代码
{
  "dependencies": [
    "fmt"
  ]
}
  1. 编写 CMakeLists.txt:在你的 CMakeLists.txt 中,使用 find_package 来查找并使用这些库。
cmake 复制代码
cmake_minimum_required(VERSION 3.10)

project(HelloWorld)

# 查找 vcpkg 中的 fmt 库
find_package(fmt CONFIG REQUIRED)

# 添加你的可执行文件
add_executable(HelloWorld main.cpp)

# 将库链接到你的目标
target_link_libraries(HelloWorld PRIVATE fmt::fmt)

完成以上配置后,CMake 在配置项目时会自动读取 vcpkg.json 并下载/安装缺失的库。

第四步:验证效果

  1. 在 VS Code 中,按 Ctrl+Shift+P 打开命令面板,运行 CMake: Configure。CMake 工具应该会自动找到并使用你配置的 vcpkg 工具链。

  2. 在你的 .cpp 文件中,尝试包含 fmt 的头文件并编写代码:

    cpp 复制代码
    #include <fmt/core.h>
    
    int main() {
        fmt::print("Hello World!\n");
        return 0;
    }

此时,代码高亮和智能提示都能正常工作。

避坑指南

  • 头文件找不到 (#include 报红):这通常是 VS Code 的 C/C++ 扩展没有获取到正确的包含路径。最可靠的解决方法是,在 .vscode/c_cpp_properties.json 文件中,将 "configurationProvider" 设置为 "ms-vscode.cmake-tools",让 CMake Tools 扩展来接管智能提示的配置。
  • 链接错误 (LNK2001 / undefined reference):这表示虽然头文件找到了,但链接器不知道要链接哪个库文件。务必确保在 CMakeLists.txt 中正确使用了 target_link_libraries。不要试图在 tasks.json 里手动指定所有路径,CMake 方式会自动处理。
  • vcpkg 命令找不到:如果没有设置系统环境变量,可以在 VS Code 的终端中临时设置。或者,只把 VCPKG_ROOT 配置在 CMakeUserPresets.jsonsettings.json 里也行,CMake 配置时会用到。
  • MSVC 编译器问题:如果在 Windows 上使用 MSVC 编译器,需要从 "Developer Command Prompt for VS" 或 "Developer PowerShell for VS" 中启动 VS Code,这样才能继承正确的编译环境变量。
  • 安装库超时:如果安装库时因为网络问题失败,可以尝试配置 Git 代理,或者从 vcpkg 的 GitHub 仓库的 releases 页面手动下载预编译的库文件。

总结

总的来说,VS Code + CMake + vcpkg 这套组合是当下 C++ 开发的主流选择。vcpkg 负责安装和管理库,CMake 负责查找和链接,而 VS Code 则提供了一个便捷的开发界面。

只要在 CMake 层面正确地配置了 CMAKE_TOOLCHAIN_FILE,并在 CMakeLists.txt 中通过 find_package 来使用库,整个流程就会非常顺畅。这样不仅解决了代码提示问题,也让项目的构建和依赖管理变得清晰、可复现。

两种工作模式

vcpkg 提供了两种工作模式,通常更推荐使用清单模式。

特性 经典模式 (Classic Mode) 清单模式 (Manifest Mode)
依赖声明 手动在命令行执行 vcpkg install 在项目根目录的 vcpkg.json 文件中声明
依赖安装 手动安装,所有项目共享同一份已安装的库 自动安装,配置CMake时自动下载并安装依赖
版本控制 难以锁定依赖版本,不同项目可能冲突 通过 vcpkg.json 中的 "builtin-baseline" 锁定所有依赖的统一版本基线
项目隔离 依赖全局安装在 <vcpkg-root>/installed 依赖安装在项目构建目录 (build/vcpkg_installed) 下,实现项目间隔离
推荐场景 个人学习、小型或临时性项目 团队协作、持续集成、需要版本精确控制的正式项目

在 CMakeLists.txt 中使用库

完成上述集成后,在你的 CMakeLists.txt 文件中,就可以使用标准的 CMake 命令来查找和使用由 vcpkg 安装的库了。

cmake 复制代码
cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 查找由 vcpkg 安装的库,例如 OpenSSL
find_package(OpenSSL REQUIRED)

# 添加你的可执行文件
add_executable(my_app main.cpp)

# 将库链接到你的目标
target_link_libraries(my_app PRIVATE OpenSSL::SSL OpenSSL::Crypto)

注意:find_package 命令必须在调用 project() 命令之后,但所有影响 vcpkg 行为的自定义变量(如 VCPKG_TARGET_TRIPLET)都必须在第一个 project() 之前设置。

总结

vcpkg 和 CMake 的组合是现代 C++ 开发的主流实践之一,它帮助你从繁琐的"下载源码、编译、配置路径"中解放出来,让你能更专注于项目本身的开发。

建议:对于新项目,直接采用清单模式。你只需要创建 vcpkg.json 列出依赖,并在配置 CMake 时正确指定工具链文件,vcpkg 会自动处理剩下的一切。这种方式不仅干净,而且保证了项目环境的一致性。

vcpkg.json

编写 vcpkg.json 是使用 vcpkg 清单模式的核心。这个文件用于声明项目的依赖、版本和功能等信息。

基础示例:一个最简单的清单

最基础的 vcpkg.json 文件只包含项目名称、版本号和依赖项。

json 复制代码
	{
  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
  "name": "my-application",
  "version": "1.0.0",
  "dependencies": [
    "fmt",
    "zlib"
  ]
}

说明:

  • $schema 字段虽然不是必需的,但强烈推荐。它能让你在支持 JSON Schema 的编辑器(如 VS Code)中获得智能提示和语法检查。
  • name 字段必须是小写字母、数字和连字符 (-) 的组合,不能以连字符开头或结尾。
  • dependencies 列出了项目直接依赖的库,如 fmtzlib

常用字段详解

除了基础字段,vcpkg.json 还有许多强大的功能,下面用表格来介绍最常见的几个。

字段 说明 示例
dependencies 项目的核心依赖列表。可以只写库名(字符串),也可以用对象形式进行更精细的控制。 "dependencies": [ "fmt", { "name": "libarchive", "default-features": false } ]
builtin-baseline 版本控制的基石。它通过指定 vcpkg 官方仓库的一个 Git 提交 ID,来锁定所有依赖项的最低基础版本,确保团队成员在不同时间、不同机器上能得到一致的依赖版本。 "builtin-baseline": "3426db05b996481ca31e95fff3734cf23e0f51bc"
overrides 精确版本控制。它会强制覆盖由 builtin-baseline 或其他依赖项传递而来的版本,将指定包固定到你想要的确切版本。使用此功能时需谨慎,因为它可能会打破依赖项的版本兼容性。 "overrides": [ { "name": "zlib", "version": "1.2.8" } ]
features 为你的项目自身定义可选的功能组件。每个功能可以有自己的描述和专属依赖项,方便按需构建项目的不同部分(如客户端、服务器)。 见下文"项目功能示例"
license 声明项目的开源许可证。应使用标准的 SPDX 许可证表达式(如 "MIT", "LGPL-2.1-only")。 "license": "MIT"
description 对项目的简短描述。对于要提交到 vcpkg 公共注册表的库,这是必填项。 "description": "A modern formatting library for C++."

进阶用法示例

精细控制依赖项和"功能"(Features)

许多库提供可选的功能模块,vcpkg 允许你精确选择安装哪些功能,从而减小项目体积和编译时间。

下面的例子展示了如何添加 libarchive 库,并只启用其 bzip2 功能,同时关闭所有默认功能:

json 复制代码
{
  "dependencies": [
    {
      "name": "libarchive",
      "default-features": false,  // 关闭 libarchive 的默认功能
      "features": [ "bzip2" ]      // 只开启 bzip2 功能
    }
  ]
}

如何知道一个库有哪些功能? 你可以在项目目录下(或任何有清单文件的地方)使用命令 vcpkg search <库名> 来查看。输出中,以 库名[功能名] 形式列出的就是该库支持的功能。

平台相关的依赖

你可能需要某个只在特定操作系统上才需要的库。可以使用 platform 字段,配合平台表达式来实现:

json 复制代码
{
  "dependencies": [
    {
      "name": "picosha2",
      "platform": "!windows"    // 只有在非 Windows 平台上才依赖 picosha2
    },
    {
      "name": "winhttp",
      "platform": "windows"      // 只有在 Windows 平台上才依赖 winhttp
    }
  ]
}

为你的项目定义"功能"(Features)

如果你的项目有多个版本(比如免费版和付费版,或客户端和服务端),可以为它们定义不同的功能:

json 复制代码
{
  "name": "my-game",
  "version": "1.0.0",
  "dependencies": [ "grpc" ],
  "features": {
    "client": {
      "description": "Build the game client",
      "dependencies": [ "sdl2", "bullet3" ]
    },
    "server": {
      "description": "Build the dedicated server",
      "dependencies": [ "proxygen" ]
    }
  }
}

当使用 CMake 集成时,你可以通过设置 VCPKG_MANIFEST_FEATURES 变量来选择构建哪个功能组件。

实用工具与技巧

  • 初始化清单文件:在项目根目录下打开终端,运行 vcpkg new --application 命令。这会自动为你创建一个基础的 vcpkg.json 文件和一个 vcpkg-configuration.json 配置文件。
  • 添加依赖:使用 vcpkg add port <库名> 命令,vcpkg 会自动将依赖写入 vcpkg.json 文件中。
  • IDE 支持:主流的 IDE 都对 vcpkg.json 提供了良好的支持。例如,在 Qt Creator 中,你可以通过图形化界面来创建和编辑清单文件。

总结

编写 vcpkg.json 的核心思路是声明式依赖管理。你只需要在清单中清晰地列出项目的需求,vcpkg 就会自动完成依赖的安装、版本控制和配置工作。

对于大多数新项目,一个包含 name、version、dependencies 和 builtin-baseline 字段的清单就是一个很好的起点。

相关推荐
AOwhisky3 小时前
Kubernetes调度与服务暴露:从“定时任务”到“服务发现”的完全指南
linux·运维·云原生·容器·kubernetes·服务发现
wljy13 小时前
牛客每日一题(2026.4.30) 整数域二分
c语言·c++·算法·蓝桥杯·二分
白夜11174 小时前
C++任务调度与状态机
开发语言·c++·笔记
hahaha 1hhh4 小时前
中文乱码 ubuntu autodl
linux·运维·前端
计算机安禾4 小时前
【Linux从入门到精通】第37篇:NFS网络文件系统——无状态的数据共享
linux·网络·php
暴力求解4 小时前
Linux---保存信号
linux·运维·服务器·开发语言·操作系统
Bruce_Liuxiaowei4 小时前
CVE-2026-31431 (Copy Fail) 漏洞复现与验证记录
linux·安全·漏洞复现·cve-2026-31431
王老师青少年编程4 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【反悔贪心】:建筑抢修
c++·算法·贪心·反悔贪心·csp·信奥赛·建筑抢修