vcpkg 与 CMake 集成

本节以搭建一个迷你 gRPC 服务器为例,使用 vcpkg 管理依赖,基于 CMake 构建整个项目。

任何 CMake 清单文件第一条语句必须是 cmake_minimum_required,用于指定 CMake 的最低版本要求:

cmake_minimum_required(VERSION 3.20)

要使用 vcpkg,需要确保 VCPKG_ROOT 环境变量设置。在使用 Visual Studio 2022 及以上版本(需要确保 vcpkg 功能开启)开发者 Shell 时,该环境变量会预先配置好。在 CMake 中,可使用 $ENV:{VCPKG_ROOT} 来引用该环境变量:

message(STATUS "vcpkg root: $ENV{VCPKG_ROOT}")

为了让 CMake 能找到 vcpkg 安装的库,需要在 CMakeLists.txt 中添加以下行:

# vcpkg toolchain must be specified before the first project()/enable_language so its hooks add the package paths
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "vcpkg toolchain file")

vcpkg 基于源码构建依赖,首次构建非常耗时。 默认情况下,vcpkg 会在 CMAKE_BINARY_DIR 目录下创建 vcpkg_installed 目录,所有的构建产物放到此目录下。 考虑到构建耗时问题,如果删除了构建目录(如 build),再次构建又需要重新从源码构建依赖。 因此,我个人习惯重新定义 VCPKG_INSTALLED_DIR,将 vcpkg 构建的依赖放到源码目录下,并在 .gitignore 中忽略 vcpkg_installed

# Keep manifest-installed packages outside the build tree so deleting build/ does not force reinstall.
set(VCPKG_INSTALLED_DIR "${CMAKE_SOURCE_DIR}/vcpkg_installed" CACHE PATH "vcpkg installed tree" FORCE)

工具链文件必须在 project()enable_language() 之前指定,以便 CMake 的钩子能够正确添加 vcpkg 包的路径。

其他集成方案

除了在 CMakeLists.txt 中指定工具链文件外,还可以通过命令行参数 -DCMAKE_TOOLCHAIN_FILE 来指定 vcpkg 的工具链文件:

cmake -DCMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake ..

CMake 3.19 之后,提供了预设(presets)功能,可以在 CMakePresets.json 中配置 vcpkg 的工具链文件:

{
  "version": 3,
  "configurePresets": [
    {
      "name": "gRPC-demo",
      "cacheVariables": {
        "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
      }
    }
  ]
}

使用预设 JSON 文件的方式更加简洁,且不需要修改 CMakeLists.txt 文件,在真实的项目中更推荐使用预设 JSON 文件的方式。

随后,指定项目名称和使用的 C++ 标准:

project(gRPC-demo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

现在,可以使用 find_package 来查找 vcpkg 安装的库了。

find_package(gRPC CONFIG REQUIRED)
find_package(Protobuf CONFIG REQUIRED)