【CMake 系列】(二)第三方依赖管理

接着上次的【CMake系列】(一)入门 继续讲。git

此次,主要说说 CMake 的依赖管理。github

依赖管理

当咱们说 CMake 的依赖管理的时候,每每说的是 C/C++ 项目的依赖管理,可是这门古老的语言,到目前为止,仍是没有一个官方大一统的依赖管理工具。npm

而回头看看它的后来者,Ruby 有 gem、Node.js 有 npm、 Golang 有 go mod、Rust 有 cargobash

你可能会提到 C++ 在 C++20 中,引入了 Module,只是目前 编译器的支持 仍是不够,更别提那些著名 C++ 项目的支持了。假如以后能作到如现代语言一条命令安装完全部依赖就能直接使用的话,家祭无忘告乃翁。服务器

那么,CMake 给咱们提供了什么样的支持?能够这么说,支持 CMake 的项目,基本上都会提供一个相似于 xxx-config.cmake 或者 xxxConfig.cmake 的文件,它们的做用就是提供查找与引入到当前项目以供使用。工具

CMake find_package

先来看看它长什么样:性能

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NO_POLICY_SCOPE])

因而,若是你须要引入 OpenCV 这个依赖,那么,你就须要在你编译项目文件以前,写上那么一句话:code

find_package(OpenCV 3.4.9 REQUIRED)

这句话的就说明,你须要查找 OpenCV 这个依赖,而且版本是 3.4.9(版本的兼容逻辑由包本身控制,若是不是 EXACT的话它会自动查找兼容的包),且不能缺乏,也就是 REQUIRED。固然,若是你不是必需要这个依赖,可使用 QUIET 这个关键字。component

而后在须要用到的地方:blog

target_link_libraries(lib PUBLIC ${OpenCV_LIBS})

注意这里的 PUBLIC 关键字,这个关键字表示,若是有其它的库或者可执行程序依赖 lib,那么你不用再次声明须要 OpenCV 相关的库了,CMake 会自动将依赖加进去。另外,若是你使用的是 CMake 3.5 版本如下的话,还须要这样作:

target_include_directories(lib PUBLIC ${OpenCV_INCLUDE_DIRS})

另外,若是你查找的依赖,须要子模块依赖,好比 Boost,你就要用到 COMPONENTS 或者 OPTIONAL_COMPONENTS

find_package(Boost 1.50 REQUIRED COMPONENTS filesystem)
target_link_libraries(lib PUBLIC Boost::filesystem)

第三方依赖管理

如今问题来了,我既然能够用 find_package 这么方便地管理包,那查找的包怎么来呢?

同窗,这才是关键,若是你作的是本地机器开发,那么有部分能够直接安装(另外也有部分的交叉编译库,能够搜索肯定),好比在 Ubuntu 上面,你须要 OpenCV 的话,直接 sudo apt install libopencv-dev 便可,而在 MacOS 上,能够 brew install opencv

若是你是在进行交叉编译,或者目前系统中的开发库版本不知足要求,那么,你就要进行源码编译了。

这时候,问题就来了,源码如何放在咱们开发的项目中?直接拷贝进来?看过我以前 如何克隆一个大 Git 项目 文章的同窗,这个错误就不要犯了。

那该如何操做?很简单,可使用 git submodule

你能够将相应的代码库放在专门的文件夹下,好比 extern 或者 third_party 等等。

而后经过相似这样的命令: git submodule add https://github.com/opencv/opencv -b 3.4 extern/opencv 来添加便可。

对于用户,它须要 git submodule update --init --recursive,或者在克隆的时候添加 --recursive 参数。

而后,你须要在你的 CMakeLists.txt 中,加入额外的配置步骤,若是项目的 CMakeLists.txt 支持当作模块,你能够直接添加为子目录:add_subdirectory(extern/opencv)

我尝试过这种方式,可是遇到了一时没法解决的交叉编译的问题,就放弃了,由于有些项目写的 CMakeLists.txt 并不标准,不支持它做为其它项目的子模块,而且也不是全部项目都支持 CMake。固然,你也能够经过给项目写 patch 来修改,或者经过写专门的 bash 脚原本解决。

这里有个前提,它须要使用者知道 git submodule 的使用方案,若是你不喜欢这种方式,你还有其它三个方案:

  1. ExternalProject:编译时运行,没法在配置时使用 add_subdirectory
  2. DownloadProject:配置时运行,能够 add_subdirectory
  3. FetchContent (CMake 3.11+):方案二的官方版本,更简便一些,只是在比较高的版本才有,鉴于目前大部分机器上的 CMake 版本比较低,可能会要求用户升级后才能使用;

目前,我在团队项目中,使用的是 ExternalProject,为何?由于单独做为一个步骤,这样能够预先编译好各个平台依赖的库,节约其它团队成员没必要要的时间。

我将相关的第三方依赖作成能够一行命令编译的版本,这样每次均可以在服务器上,利用服务器高性能 CPU 快速编译好,而后将生成物直接保存在公共存储空间,最后其余人使用的时候,能够直接下载使用,固然这里会对产物进行签名验证。

而且,连下载的步骤也能够经过 CMake 在配置阶段,直接下载使用,大大提升了团队的开发效率。


感谢阅读,本文首发于 Github issues: https://github.com/xizhibei/b... (Star 以及 Watch 强烈暗示 🙈);另外这篇文章也能在本人博客内阅读:https://blog.xizhibei.me/2020...

本文采用 署名-非商业性使用-相同方式共享(BY-NC-SA)进行许可。

相关文章
相关标签/搜索