使用CPM管理CMake C++工程中的外部依赖库

严正声明:本文系作者davidhopper原创,未经许可,不得转载。

众所周知,对于外部依赖库的管理是CMake C++工程中一个令人头疼的问题。人们一直希望能有一个工具来自动配置CMake C++工程的外部依赖库。现在,这个自动化工具终于诞生了,这就是CPM(https://github.com/cpm-cmake/CPM.cmake)。只要电脑连接了互联网,任何CMake C++项目都可借助 CPM 添加外部依赖库。
CPM的优缺点分别为:

  • 优点

  • 极其轻量化,即插即用,无需安装,仅需下载一个CPM.cmake脚本文件;

  • 跨平台 ,可用于任何操作系统;

  • 可与Git联合使用实现对依赖库的版本管理。

  • 不足

  • 所有依赖库最初都要从网上下载构建,如离线使用需设置环境变量:CPM_SOURCE_CACHE 。

一、下载CPM

将CPM加入当前CMake工程,仅需从GitHub网站下载最新版本的CPM.cmake脚本文件,或者从其他项目中将该文件复制到当前项目。
从GitHub网站下载的命令如下所示:

# 在当前项目的根目录创建cmake目录
mkdir cmake
# 下载CPM.cmake文件到cmake目录
wget -O cmake/CPM.cmake https://github.com/cpm-make/CPM.cmake/releases/latest/download/get_cpm.cmake

说明:国内因为墙的原因,访问GitHub网站网速很慢,一般难以下载成功(说明:反正我在不用代理情况下没有下载成功过)。要解决该问题,可以使用代理。如无代理,也可以从Gitte网站寻找替代源。例如,我在Gitte网站找到了一个替代源(版本不是最新),直接将其克隆下来,命令如下所示:

git clone https://gitee.com/hejuncheng1/CPM.cmake

之后,再将该工程中的“CPM.cmake”文件复制到当前CMake项目:

# 在当前项目的根目录创建cmake目录
mkdir cmake
# 将“CPM.cmake”文件复制到cmake目录
# ~/code/CPM.cmake需要修改为你的实际地址
cp ~/code/CPM.cmake/cmake/CPM.cmake ./cmake

二、完整使用语法

CPM语法简单,使用方便,通过调用CPMAddPackage就可安装一个外部库,具体语法如下:

CPMAddPackage(
  NAME          # 依赖库的唯一名称,一般是网页链接,如果是GitHub依赖库,还需通过GITHUB_REPOSITORY属性指定GitHub仓库名
  VERSION       # 依赖库的最低版本号(可选,缺省为0)
  OPTIONS       # 传递给依赖库的配置选项(可选)
  DOWNLOAD_ONLY # 如设置,则从网上下载依赖库(可选)
  [...]         # 依赖库的源,用于转发给CMake自带的FetchContent_Declare函数(可选),详见下文描述。
)

上述语法中的[...]表示依赖库的源,用于转发给CMake自带的FetchContent_Declare函数。源可以通过GIT_REPOSITORY指定,也可直接通过URL地址指定,例如https://example.com/my-package-1.2.3.zip。如果源由GIT_REPOSITORY指定,可使用GIT_TAG指定依赖库的版本号;如不使用GIT_TAG,则依赖库的版本号由VERSION指定。GIT_TAG 也可以设置为特定的提交(即Git的commit id,例如64913822041ca9c7a30f5c61fe4584577a3df3e9)或分支名称(即Git的branch,例如 master),但不建议这样做,因为在此情况下依赖库仅在缓存清除时才会更新。如果额外的可选参数EXCLUDE_FROM_ALL设置为真值,则默认情况下不会构建依赖库中定义的任何目标。

示例:添加GitHub网站中的依赖库googletest,配置如下:

CPMAddPackage(
  NAME googletest   # 添加依赖库:googletest
  GITHUB_REPOSITORY google/googletest # GitHub仓库是:google/googletest,CPM会在GitHub网站找到该仓库,并得到对应的仓库链接:https://github.com/google/googletest
  GIT_TAG release-1.8.1 # Git标签是release-1.8.1
  VERSION 1.8.1 # 版本号是1.8.1
  OPTIONS  # 可选参数包括:INSTALL_GTEST:关,gtest_force_shared_crt,开
      "INSTALL_GTEST OFF"
      "gtest_force_shared_crt ON"
)

三、简单使用语法

以上完整语法过于啰嗦,可使用更为简洁的形式:

# 通过URI添加依赖库
CPMAddPackage("uri")
# 通过URI添加指定版本号的依赖库
CPMAddPackage("uri@version")
# 通过URI添加指定标签的依赖库
CPMAddPackage("uri#tag")
# 通过URI添加指定版本号和指定标签的依赖库
CPMAddPackage("uri@version#tag")

uri”指网址,例如“https://example.com/my-package-1.2.3.zip”,GitHub、GitLab、BitBucket等开源代码库网址可以使用缩写形式,如下表所示:

序号缩写网址完整网址
1gh:user/namehttps://github.com/user/name.git
2gl:user/namehttps://gitlab.com/user/name.git
3bb:user/namehttps://bitbucket.org/user/name.git

以下是相关示例:

# 基于URL添加依赖库,版本号依据网址内容推断为:1.2.3
CPMAddPackage("https://example.com/my-package-1.2.3.zip")
# 基于URL添加依赖库,版本号依据网址内容推断为:1.2.3,并基于给定的MD5码作依赖库完整性验证
CPMAddPackage("https://example.com/my-package-1.2.3.zip#MD5=68e20f674a48be3使用8d60e129f600faf7d")
# 基于URL添加依赖库,版本号显式地指定
CPMAddPackage("https://example.com/my-package.zip@1.2.3")
# 基于GitHub网址添加依赖库,依赖库名Catch2,版本号为:2.5.0
# gh:catchorg/Catch2对应的完整网址为:https://github.com/catchorg/Catch2.git
CPMAddPackage("gh:catchorg/Catch2@2.5.0")
# 基于GitHub网址添加依赖库,依赖库名json,版本号为:3.9.1
# gh:nlohmann/json对应的完整网址为:https://github.com/lohmann/json.git
CPMAddPackage("gh:nlohmann/json@3.9.1")

四、补充说明

调用CPMAddPackage, 以下变量将在当前CMake工程的作用域内定义:

  • <dependency>_SOURCE_DIR
  • <dependency>_BINARY_DIR
  • <dependency>_ADDED

<dependency>是依赖库名。例如通过CPMAddPackage添加依赖库boost后,将在CMake工程的作用域内定义如下变量:boost_SOURCE_DIR、boost_BINARY_DIR、boost_ADDED。

几个特殊变量的说明:
  • CPM_SOURCE_CACHE

为了避免从网上重新下载依赖库,可以使用CPM_SOURCE_CACHE。只要依赖库之前已经下载过,CMake项目在离线状态下就可以使用之前下载的缓存,而不会反复到网上去下载。传递该参数的方法如下:

# /path/to/local/dep表示依赖库的本地缓存路径,也就是之前已下载好的依赖库目录
cmake -Bbuild -DCPM_SOURCE_CACHE=/path/to/local/dep

当然,也可直接在配置文件.bashrc.bash_profile中,添加上述变量:.

export CPM_SOURCE_CACHE=${HOME}/.cache/CPM
  • CPM_DOWNLOAD_ALL
    若设置该变量,CPM会下载所有依赖库。该变量同样可以通过cmake命令传递或通过配置文件配置,如上所示。

  • CPM_USE_LOCAL_PACKAGES

  • CPM_LOCAL_PACKAGES_ONLY
    如果本机已安装有依赖库,无需从网上下载,可使用CPM_USE_LOCAL_PACKAGES,这样CPM就会使用CMake的find_package函数在本机查找依赖库,如找不到再从网上下载。如果CPM_LOCAL_PACKAGES_ONLY被设置,则CPM只会在本机寻找依赖库,如果本机没有安装依赖库,将报本地依赖库不存在的错误。

五、完整示例

以下是一个使用CPM管理依赖库的一个完整示例。

cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

# 创建工程,名称为:MyProject
project(MyProject)

# 基于test.cpp生成可执行文件tests
add_executable(tests tests.cpp)

# 添加对其他库的依赖
# 首先包含cmake/CPM.cmake文件,以便CPM能够生效
include(cmake/CPM.cmake)
# 使用简洁语法从GitHub网站添加一个依赖库Catch2,版本号为2.5.0
CPMAddPackage("gh:catchorg/Catch2@2.5.0")

# 使用完整语法直接基于URL添加另一个依赖库nlohmann_json,版本号为3.7.3
# 当然也可使用简洁语法从GitHub网站添加,如下所示。这是只是为了描述不同的用法故意这么做而已
# CPMAddPackage("gh:nlohmann/json@3.7.3")

CPMAddPackage(
  NAME nlohmann_json
  VERSION 3.7.3
  # the git repo is incredibly large, so we download the archived include directory
  URL https://github.com/nlohmann/json/releases/download/v3.7.3/include.zip
  URL_HASH SHA256=87b5884741427220d3a33df1363ae0e8b898099fbc59f1c451113f6732891014
)

# 生成可执行文件tests时,需要链接依赖库Catch2、nlohmann_json 
target_link_libraries(tests Catch2 nlohmann_json)
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
假设我们有一个动态 `libfoo.so`,并且我们想在 C++ 代码使用它。下面是一个简单的示例: 首先,我们需要编写一个 CMakeLists.txt 文件来指示 CMake 如何生成我们的可执行文件和链接我们的动态。假设我们的源代码文件是 `main.cpp`,我们的动态位于 `/path/to/libfoo.so`。我们可以这样编写 CMakeLists.txt 文件: ```cmake cmake_minimum_required(VERSION 3.10) project(MyProject) # 添加可执行文件 add_executable(my_executable main.cpp) # 添加动态目录和名称 link_directories(/path/to) target_link_libraries(my_executable foo) ``` 其,我们使用 `add_executable` 命令来创建一个名为 `my_executable` 的可执行文件,并将 `main.cpp` 添加为源文件。然后,我们使用 `link_directories` 命令来指定我们的动态所在的目录,并使用 `target_link_libraries` 命令将动态链接到我们的可执行文件。 接下来,我们需要在 C++ 代码包含动态的头文件并使用的函数。假设我们的动态定义了一个名为 `foo` 的函数,我们可以这样编写 `main.cpp`: ```cpp #include <iostream> #include "foo.h" int main() { std::cout << foo() << std::endl; return 0; } ``` 在这个例子,我们包含了 `foo.h` 头文件并调用了 `foo` 函数,并将其输出到标准输出。 最后,我们可以使用以下命令来编译和运行我们的代码: ```bash mkdir build cd build cmake .. make ./my_executable ``` 这将生成一个名为 `my_executable` 的可执行文件,并将动态链接到其。当我们运行可执行文件时,它将调用 `foo` 函数并将其输出到控制台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值