第93章:使用Hunter:集成Hunter包管理器

说实话,C++的包管理一直是个让人头疼的问题。Python有pip,JavaScript有npm,Java有Maven,而我们C++开发者呢?还在手动下载源码、编译、配置路径。我早期做项目时,光折腾第三方库就能耗掉半天时间。后来接触到Hunter,才算是找到了一个比较顺手的解决方案。

Hunter是什么?

Hunter本质上是一个CMake的包管理框架。它基于CPM(CMake Package Manager)发展而来,但功能更完善。说白了,你只需要在CMakeLists.txt里声明依赖,Hunter就会自动帮你下载、编译、链接。

我个人习惯把Hunter看作「C++世界的apt-get」。你想想看,写个hunter_add_package(Boost),Boost库就自动配置好了,多省心。

核心优势:

  • 无需手动下载源码包
  • 自动处理依赖关系
  • 支持版本锁定,保证构建可复现
  • 与CMake深度集成,开箱即用

快速上手:第一个Hunter项目

我们先从一个最简单的例子开始。假设你的项目需要用到fmt库(格式化输出库)。

第一步,在项目根目录创建CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

# 启用Hunter
include("cmake/HunterGate.cmake")
HunterGate(
    URL "https://github.com/cpp-pm/hunter/archive/v0.23.251.tar.gz"
    SHA1 "5659b15dc0884d4b03dbd95710e6a1d0d0a9d3e7"
)

project(MyFirstHunterProject LANGUAGES CXX)

# 添加fmt包
hunter_add_package(fmt)
find_package(fmt CONFIG REQUIRED)

add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE fmt::fmt)

第二步,创建cmake/HunterGate.cmake文件。这个文件可以从Hunter的GitHub仓库下载,也可以直接用我下面这个精简版:

# Copyright (c) 2013-2019, Ruslan Baratov
# 从Hunter官方仓库获取最新版本
# https://raw.githubusercontent.com/cpp-pm/hunter/master/cmake/HunterGate.cmake

第三步,写个简单的main.cpp测试一下:

#include <fmt/core.h>

int main() {
    fmt::print("Hello from Hunter!\n");
    fmt::print("The answer is {}\n", 42);
    return 0;
}

然后执行:

mkdir build && cd build
cmake ..
cmake --build .
./my_app

嗯,这里要注意:第一次构建时,Hunter会下载并编译所有依赖,所以会比较慢。但后续构建就快多了,因为缓存机制会起作用。

Hunter的工作流程

我画了一张图,帮你理解Hunter到底在背后做了什么:

Hunter包管理器工作流程 CMake解析 读取CMakeLists.txt HunterGate初始化 下载Hunter框架 解析依赖 hunter_add_package 检查本地缓存 ~/.hunter/_Base/ 目录 ✅ 缓存命中 ❌ 缓存未命中 下载并编译 从GitHub拉取源码 配置完成 find_package可用

流程其实不复杂:CMake解析你的项目 → HunterGate初始化 → 解析依赖 → 检查本地缓存 → 如果缓存未命中则下载编译 → 最终配置完成。

版本锁定:保证构建可复现

我在项目中遇到过最头疼的事:同事的机器上构建通过,我的机器上就报错。原因往往是第三方库版本不一致。

Hunter通过HunterGate的URL和SHA1来锁定版本。你还可以创建hunter/config.cmake文件来精细控制每个包的版本:

# hunter/config.cmake
hunter_config(fmt VERSION 8.1.1)
hunter_config(spdlog VERSION 1.10.0)
hunter_config(Boost VERSION 1.79.0)

这样团队里所有人都用完全相同的版本,再也不会出现「我这边能编译啊」的尴尬情况。

常用包一览

Hunter支持超过150个常用C++库。我整理了一些高频使用的:

包名 用途 Hunter中的名称
fmt 格式化输出 fmt
spdlog 日志系统 spdlog
Boost 通用C++库 Boost
nlohmann_json JSON解析 nlohmann_json
gtest 单元测试 GTest
OpenCV 计算机视觉 OpenCV
protobuf 序列化 protobuf

小技巧:如果你不确定某个包在Hunter中的确切名称,可以查看Hunter的官方包列表:https://github.com/cpp-pm/hunter/tree/master/cmake/projects。每个子目录名就是包名。

实际项目中的配置示例

下面是一个更完整的例子,展示了如何在真实项目中使用Hunter:

cmake_minimum_required(VERSION 3.15)

include("cmake/HunterGate.cmake")
HunterGate(
    URL "https://github.com/cpp-pm/hunter/archive/v0.23.251.tar.gz"
    SHA1 "5659b15dc0884d4b03dbd95710e6a1d0d0a9d3e7"
)

project(MyServer LANGUAGES CXX)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 添加依赖
hunter_add_package(spdlog)
hunter_add_package(nlohmann_json)
hunter_add_package(GTest)

find_package(spdlog CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(GTest CONFIG REQUIRED)

# 添加可执行文件
add_executable(my_server
    src/main.cpp
    src/server.cpp
    src/handler.cpp
)

target_link_libraries(my_server
    PRIVATE
    spdlog::spdlog
    nlohmann_json::nlohmann_json
)

# 添加测试
add_executable(my_tests
    tests/test_server.cpp
    tests/test_handler.cpp
)

target_link_libraries(my_tests
    PRIVATE
    GTest::GTest
    GTest::Main
    spdlog::spdlog
)

enable_testing()
add_test(NAME server_tests COMMAND my_tests)

注意事项:

  • HunterGate的URL和SHA1必须匹配,否则会报错
  • 第一次构建时网络必须通畅,因为需要下载Hunter框架和所有依赖
  • 如果公司网络受限,可以配置代理或搭建本地Hunter缓存服务器
  • 不要将build目录提交到版本控制中

避坑指南

我曾经在一个项目里踩过一个坑:项目用了Hunter,但团队成员分布在不同的网络环境下。有人能正常构建,有人卡在下载步骤。后来我们统一搭建了一个内部的Hunter缓存服务器,才彻底解决这个问题。

另外,如果你发现某个包在Hunter中版本较旧,可以尝试在hunter/config.cmake中指定更新的版本。但要注意,不是所有版本都经过Hunter的完整测试,升级前最好先验证一下。

还有个常见问题:有些包(比如OpenCV)体积很大,编译时间很长。我的建议是,如果只是用OpenCV的某个模块,可以考虑只引入需要的组件,或者使用预编译版本。

总结

Hunter让C++的包管理变得简单多了。你不需要再手动下载源码、配置路径、处理依赖。写一行hunter_add_package,剩下的交给Hunter就好。

我个人觉得,对于中小型项目,Hunter是个非常不错的选择。它没有Conan那么重,也没有纯手动管理那么累。如果你还在为C++的依赖管理发愁,不妨试试Hunter。


公众号:蓝海资料掘金营,微信deep3321