【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)進行許可。

相關文章
相關標籤/搜索