深入理解CMake(3):find_package()的使用

created in 2019-03-03 11:44:11
updated in 2019-3-28 14:31:21

依賴包的實(shí)際情況:找不到邻吭,不知道如何切換版本

前面兩篇從cmake源碼中命令行入口參數(shù)枉侧、Caffe源碼頂層CMakeLists.txt進(jìn)行了解讀怒竿,整體有了一個(gè)印象饿悬。在此基礎(chǔ)上令蛉,考慮實(shí)際中最常遇到的問題:基于CMake構(gòu)建Caffe,如何確保每一個(gè)依賴被正確找到狡恬?盡管用了CMake用了find_package()珠叔,也看到了Caffe官方的CI構(gòu)建腳本scripts/install-deps.sh,但是自己機(jī)器不是docker環(huán)境弟劲、如何切換多個(gè)版本的依賴包祷安?

find_package()命令是用來查找依賴包的,理想情況下兔乞,一句find_package()把一整個(gè)依賴包的頭文件包含路徑汇鞭、庫(kù)路徑、庫(kù)名字庸追、版本號(hào)等情況都獲取到霍骄,后續(xù)只管用就好了。但實(shí)際中往往CMake失敗就是出在find_package()的失敗上(這里不考慮后續(xù)make/nmake/msbuild以及編譯器淡溯、鏈接器直接執(zhí)行時(shí)的編譯读整、鏈接出錯(cuò),只討論cmake根據(jù)CMakeLists.txt執(zhí)行時(shí)候的情況)血筑,例如:

  • 多個(gè)OpenCV版本的問題
    • apt或brew等系統(tǒng)包管理工具安裝的opencv绘沉,和手動(dòng)編譯的OpenCV共存問題
    • 手動(dòng)編譯安裝了多個(gè)版本的OpenCV問題,也許你同時(shí)需要opencv2和opencv3豺总,甚至opencv4
  • 多個(gè)protobuf版本問題
    • protobuf的python包需要和proto C編譯器protoc版本一致车伞,否則帶python layer的prototxt解析失敗
    • 安裝了TensorFlow時(shí)被迫安裝的protobuf3,但是Caffe這邊用的python2喻喳,python protobuf包的版本問題

上面列出的opencv和protobuf是重災(zāi)區(qū)另玖,還有沒有列出來的比如boost版本問題等。解決起來也不難:

  • 明確find_package()的N大查找順序
  • 知道如何讓find_package()找到非CMake構(gòu)建安裝的依賴包

find_package()原理解讀

根據(jù)cmake官方文檔可以知道表伦,find_package()有Module模式(基本用法谦去,basic signature)和Config模式(full signature,完全用法)蹦哼,其中Module模式是基礎(chǔ)鳄哭,Config模式則更復(fù)雜高級(jí)些。

區(qū)分Module模式和Config模式

Module模式也就是基礎(chǔ)用法(Basic Signature纲熏,這里Signature表示“用法”妆丘,而不是“簽名”)锄俄,Config模式也就是高級(jí)用法(Full Signature)。

The CONFIG option, the synonymous NO_MODULE option, or the use of options not specified in the basic signature all enforce pure Config mode. In pure Config mode, the command skips Module mode search and proceeds at once with Config mode search.

也就是說勺拣,只有這3種情況下才是Config模式:

  • find_package()中指定CONFIG關(guān)鍵字
  • find_package()中指定NO_MODULE關(guān)鍵字
  • find_package()中使用了不在"basic signature"(也就是Module模式下所有支持的配置)關(guān)鍵字

換句話說奶赠,只要我不指定"CONFIG",不指定“NO_MODULE"药有,也不使用"full signature"中的關(guān)鍵字毅戈,那我就是在Module模式。排查find_package()的第一步愤惰,應(yīng)當(dāng)判斷它是Module模式還是Config模式苇经。

find-package.jpg
image.png

Module模式下find_package()的用法

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]

         [REQUIRED] [[COMPONENTS] [components...]]
         [OPTIONAL_COMPONENTS components...]
         [NO_POLICY_SCOPE])

Module模式下,相比于Config模式羊苟,可選配置參數(shù)少一些塑陵,并且如果按用戶指定的配置卻找不到包,就會(huì)自動(dòng)進(jìn)入Config模式(如上圖所示)蜡励。

關(guān)鍵字解釋
versionEXACT: 都是可選的令花,version指定的是版本,如果指定就必須檢查找到的包的版本是否和version兼容凉倚。如果指定EXACT則表示必須完全匹配的版本而不是兼容版本就可以兼都。

QUIET 可選字段,表示如果查找失敗稽寒,不會(huì)在屏幕進(jìn)行輸出(但是如果指定了REQUIRED字段扮碧,則QUIET無效,仍然會(huì)輸出查找失敗提示語(yǔ))杏糙。

MODULE 可選字段慎王。前面提到說“如果Module模式查找失敗則回退到Config模式進(jìn)行查找”,但是假如設(shè)定了MODULE選項(xiàng)宏侍,那么就只在Module模式查找赖淤,如果Module模式下查找失敗并不回落到Config模式查找。

REQUIRED可選字段谅河。表示一定要找到包咱旱,找不到的話就立即停掉整個(gè)cmake。而如果不指定REQUIRED則cmake會(huì)繼續(xù)執(zhí)行绷耍。

COMPONENTS吐限,components:可選字段,表示查找的包中必須要找到的組件(components)褂始,如果有任何一個(gè)找不到就算失敗诸典,類似于REQUIRED,導(dǎo)致cmake停止執(zhí)行崎苗。

OPTIONAL_COMPONENTScomponents:可選的模塊狐粱,找不到也不會(huì)讓cmake停止執(zhí)行赘阀。

Module模式查找順序
Module模式下是要查找到名為Find<PackageName>.cmake的文件。

先在CMAKE_MODULE_PATH變量對(duì)應(yīng)的路徑中查找脑奠。如果路徑為空,或者路徑中查找失敗幅慌,則在cmake module directory(cmake安裝時(shí)的Modules目錄宋欺,比如/usr/local/share/cmake/Modules)查找。

Config模式下find_package()的用法

find_package(<PackageName> [version] [EXACT] [QUIET]
[REQUIRED] [[COMPONENTS] [components...]]
[CONFIG|NO_MODULE]
[NO_POLICY_SCOPE]
[NAMES name1 [name2 ...]]
[CONFIGS config1 [config2 ...]]
[HINTS path1 [path2 ... ]]
[PATHS path1 [path2 ... ]]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_PACKAGE_REGISTRY]
[NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
[NO_CMAKE_SYSTEM_PATH]
[NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH])

Config模式下的查找順序胰伍,比Module模式下要多得多齿诞。而且,新版本的CMake比老版本的有更多的查找順序(新增的在最優(yōu)先的查找順序)骂租。它要找的文件名字也不一樣祷杈,Config模式要找<PackageName>Config.cmake<lower-case-package-name>-config.cmake。查找順序?yàn)椋?/p>

  1. 名為<PackageName>_ROOT的cmake變量或環(huán)境變量渗饮。CMake3.12新增但汞。設(shè)定CMP0074 Policy來關(guān)閉。
    注意:如果定義了<PackageName>_DIR cmake變量互站,那么<PackageName>_ROOT 不起作用私蕾。舉例:
cmake_minimum_required(VERSION 3.13)

project(fk_cmk)

set(OpenCV_ROOT "F:/zhangzhuo/lib/opencv_249/build")

set(OpenCV_DIR "F:/zhangzhuo/lib/opencv_300/build")

find_package(OpenCV QUIET
    NO_MODULE
    NO_DEFAULT_PATH
    NO_CMAKE_PATH
    NO_CMAKE_ENVIRONMENT_PATH
    NO_SYSTEM_ENVIRONMENT_PATH
    NO_CMAKE_PACKAGE_REGISTRY
    NO_CMAKE_BUILDS_PATH
    NO_CMAKE_SYSTEM_PATH
    NO_CMAKE_SYSTEM_PACKAGE_REGISTRY
)

message(STATUS "OpenCV library status:")
message(STATUS "    version: ${OpenCV_VERSION}")
message(STATUS "    libraries: ${OpenCV_LIBS}")
message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")

實(shí)際上會(huì)找到opencv300,也就是OpenCV_DIR這一cmake變量的值最先起作用胡桃。

  1. cmake特定的緩存變量:

CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
可以通過設(shè)定NO_CMAKE_PATH來關(guān)閉這一查找順序

  1. cmake特定的環(huán)境變量

<PackageName>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
可以通過NO_CMAKE_ENVIRONMENT_PATH來跳過踩叭。

  1. HINT字段指定的路徑

  2. 搜索標(biāo)準(zhǔn)的系統(tǒng)環(huán)境變量PATH。
    其中如果是以/bin或者/sbin結(jié)尾的翠胰,會(huì)自動(dòng)轉(zhuǎn)化為其父目錄容贝。
    通過指定NO_SYSTEM_ENVIRONMENT_PATH來跳過。

  3. 存儲(chǔ)在cmake的"User Package Registry"(用戶包注冊(cè)表)中的路徑之景。
    通過設(shè)定NO_CMAKE_PACKAGE_REGISTRY斤富,或者:
    設(shè)定CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY為true,
    來避開闺兢。

  4. 設(shè)定為當(dāng)前系統(tǒng)定義的cmake變量:

CMAKE_SYSTEM_PREFIX_PATH
CMAKE_SYSTEM_FRAMEWORK_PATH
CMAKE_SYSTEM_APPBUNDLE_PATH
通過設(shè)定NO_CMAKE_SYSTEM_PATH來跳過茂缚。

  1. 在cmake的"System Package Registry"(系統(tǒng)包注冊(cè)表)中查找。
    通過設(shè)定NO_CMAKE_SYSTEM_PACKAGE_REGISTRY跳過屋谭。
    或者通過設(shè)定CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY為true脚囊。

  2. PATHS字段指定的路徑中查找。

再次總結(jié)思路:

    1. 判斷find_package()實(shí)際執(zhí)行的是module模式還是config模式
    • 1.1 find_package(<PackageName>)這樣的用法并不能看出是module模式還是config模式桐磁。要看CMAKE_MODULE_PATH或cmake安裝路徑下是否有Find<PackageName>.cmake腳本存在悔耘,并且這個(gè)腳本是否能正確的找到包。如果上述兩個(gè)位置不存在Find<PackageName>.cmake我擂,或者這個(gè)Find<PackageName>.cmake執(zhí)行失敗衬以,則進(jìn)入config模式缓艳。
    • 1.2 通過CONFIG、NO_MODULE看峻、CONFIG模式特有字段阶淘,來設(shè)定為config模式
    1. 明確<PackageName>_DIR是config模式特有的緩存變量
    • 2.1可以在find_package()前設(shè)定<PackageName>_DIR,指向包含<PackageName>Config.cmake或<lower-case-package-name>-config.cmake的目錄互妓。
      • <PackageName>_ROOT先設(shè)定溪窒,再設(shè)定<PackageName>_DIR,最后find_package(<PackageName>)冯勉;并且兩個(gè)都能找到包澈蚌,則<PackageName>_DIR起作用。
    • 2.2 也可在find_package()后使用例如打印灼狰。
    • 2.3 module模式下在find_package()前使用<PackageName>_DIR宛瞄,并不能用來幫助find_package()找到包;并且在find_package()后交胚,也并沒有<PackageName>_DIR緩存變量自動(dòng)存在份汗。
    1. 明確<PackageName>_ROOT是cmake3.12起支持的變量
    • <PackageName>_ROOT變量被find_package, find_library, find_path, find_program, find_file支持。因此承绸,盡管從find_package()文檔頁(yè)看會(huì)以為<PackageName>_ROOT只被config模式支持而不被module模式支持裸影,但是module模式下通過另外4個(gè)find命令會(huì)間接的使用到<PackageName>_ROOT,從而find_package命令的module模式間接的支持<PackageName>_ROOT變量军熏。
    • <PackageName>_ROOT設(shè)定后轩猩,find_package()的config模式會(huì)在<PackageName>_ROOT目錄及其子目錄下尋找cmake的config文件;而<PackageName>_DIR則很傻荡澎,不會(huì)在子目錄中尋找均践。
    1. 檢查路徑是否拼寫正確
      以上的3點(diǎn)是正確的,但有時(shí)候總發(fā)現(xiàn)幺蛾子摩幔,懷疑上面三點(diǎn)說的不對(duì)彤委。這時(shí)候要檢查路徑是否拼寫正確。
    • 4.1 路徑是否拼寫錯(cuò)誤或衡,比如少字母焦影、字母寫錯(cuò)、大小寫拼錯(cuò)
    • 4.2 如果使用了環(huán)境變量來構(gòu)成cmake變量封断,注意使用$ENV{varName}而不是$varName斯辰。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市坡疼,隨后出現(xiàn)的幾起案子彬呻,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闸氮,死亡現(xiàn)場(chǎng)離奇詭異剪况,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蒲跨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門译断,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人或悲,你說我怎么就攤上這事镐作。” “怎么了隆箩?”我有些...
    開封第一講書人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)羔杨。 經(jīng)常有香客問我捌臊,道長(zhǎng),這世上最難降的妖魔是什么兜材? 我笑而不...
    開封第一講書人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任理澎,我火速辦了婚禮,結(jié)果婚禮上曙寡,老公的妹妹穿的比我還像新娘糠爬。我一直安慰自己,他們只是感情好举庶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開白布执隧。 她就那樣靜靜地躺著,像睡著了一般户侥。 火紅的嫁衣襯著肌膚如雪镀琉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評(píng)論 1 299
  • 那天蕊唐,我揣著相機(jī)與錄音屋摔,去河邊找鬼。 笑死替梨,一個(gè)胖子當(dāng)著我的面吹牛钓试,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播副瀑,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼弓熏,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了俗扇?” 一聲冷哼從身側(cè)響起硝烂,我...
    開封第一講書人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后滞谢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體串稀,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年狮杨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了母截。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡橄教,死狀恐怖清寇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情护蝶,我是刑警寧澤华烟,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站持灰,受9級(jí)特大地震影響盔夜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堤魁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一喂链、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妥泉,春花似錦椭微、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至刽沾,卻和暖如春瓢剿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悠轩。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工间狂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人火架。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓鉴象,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親何鸡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子纺弊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 引用cmake學(xué)習(xí)筆記-cmakelist.txt創(chuàng)建項(xiàng)目示例cmake的介紹和使用 Cmake實(shí)踐推薦cmake...
    scott_yu779閱讀 5,890評(píng)論 0 3
  • 首先強(qiáng)烈推薦對(duì)CMake不熟的同學(xué)先看這本書《Cmake實(shí)踐》(提取碼:qgca)。 CMake說起來是個(gè)好東西骡男,...
    金戈大王閱讀 48,147評(píng)論 5 24
  • 注:首發(fā)地址 1. 前言 當(dāng)在做 Android NDK 開發(fā)時(shí)淆游,如果不熟悉用 CMake 來構(gòu)建,讀不懂 CMa...
    cfanr閱讀 24,371評(píng)論 1 53
  • CMake學(xué)習(xí) 本篇分享一下有關(guān)CMake的一些學(xué)習(xí)心得以及相關(guān)使用。 本文目錄如下: [1犹菱、CMake介紹] [...
    AlphaGL閱讀 12,246評(píng)論 11 79
  • CMake 全稱“cross platform make”拾稳,是開源、跨平臺(tái)的自動(dòng)化構(gòu)建系統(tǒng)访得。CMake 由 Kit...
    神齊閱讀 4,107評(píng)論 0 6