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.json 或 settings.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 列出了项目直接依赖的库,如 fmt 和 zlib。

常用字段详解

除了基础字段,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 字段的清单就是一个很好的起点。

相关推荐
律宏阔4 小时前
WSL Docker 端口明明空闲,但就是绑不上端口
linux·windows
律宏阔4 小时前
WSL 突然断网,无法 ping 内网或外网
linux·windows
穷人小水滴4 小时前
用容器编译 VirtualBox 虚拟机软件 (ArchLinux, podman)
linux·容器·virtualbox
乱码三千5 小时前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei375 小时前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei375 小时前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei375 小时前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化
GeW5 小时前
制造业高端化,为什么必须重估Linux和数据库?
linux
GeW5 小时前
工业场景中的Linux与数据库选型:高端化转型的技术底座
linux
yunwei375 小时前
eBPF 开发者教程: 简单的 XDP 负载均衡器
linux·后端·性能优化