CMake之find_package

首先強烈推薦對CMake不熟的同學先看這本書《Cmake實踐》(提取碼:qgca)。

CMake說起來是個好東西,可是真正用的時候并不那么容易,很容易出現各種各樣的錯誤。這不,最近就被find_package這個命令折騰得死去活來。只好花了一天半時間,看上面那本書,再查資料,總算解決了昨天遇到的問題。

問題描述

已經成功編譯了深度學習框架Caffe,例程也可以順利執行。

但是當我在自己的代碼中調用編譯好的Caffe庫時,卻出現了編譯錯誤。此前,我已經在CMakeLists.txt中添加了下面幾句話:

include_directories(/home/wjg/projects/caffe/build/install/include)
add_executable(useSSD ssd_detect.cpp)
target_link_libraries(useSSD /home/wjg/projects/caffe/build/install/lib/libcaffe.so)

執行make后,鏈接出錯,找不到libboost_system.so文件。

這一錯誤倒是給我提了個醒,我本以為自己的代碼中沒用到boost,就不必添加boost庫路徑了,誰知道libcaffe.so中用到的庫也需要手動添加進去。

這時候我才意識到動態鏈接庫和靜態鏈接庫的區別。前者在程序運行時動態加載,而后者是在編譯時就和程序結合到一起了。于是動態鏈接庫即使編譯完成,也和其它動態庫是分離的,因此每次用都要把所有涉及的動態庫全部添加進來。在我的例子中,不僅僅需要添加boost,還有atlas、protobuf等等一大堆動態鏈接庫需要添加。這個時候,一條條添加就顯得太過麻煩,可以借助find_package命令一次性添加所有與Caffe相關的動態鏈接庫。

find_package用法

使用如下方式查找Caffe庫:

find_package(Caffe REQUIRED)

如果找到Caffe庫,就可以在接下來的語句中使用Caffe_INCLUDE_DIRSCaffe_LIBRARIES這兩個變量,比如

find_package(Caffe REQUIRED)

if (NOT Caffe_FOUND)
    message(FATAL_ERROR "Caffe Not Found!")
endif (NOT Caffe_FOUND)

include_directories(${Caffe_INCLUDE_DIRS})

add_executable(useSSD ssd_detect.cpp)
target_link_libraries(useSSD ${Caffe_LIBRARIES})

問題是,很多情況下都會找不著,或者找到了錯誤的位置。要想用對find_package,就需要了解它的工作原理。

find_package原理

首先明確一點,cmake本身不提供任何搜索庫的便捷方法,所有搜索庫并給變量賦值的操作必須由cmake代碼完成,比如下面將要提到的FindXXX.cmake和XXXConfig.cmake。只不過,庫的作者通常會提供這兩個文件,以方便使用者調用。

find_package采用兩種模式搜索庫:

  • Module模式:搜索CMAKE_MODULE_PATH指定路徑下的FindXXX.cmake文件,執行該文件從而找到XXX庫。其中,具體查找庫并給XXX_INCLUDE_DIRSXXX_LIBRARIES兩個變量賦值的操作由FindXXX.cmake模塊完成。
  • Config模式:搜索XXX_DIR指定路徑下的XXXConfig.cmake文件,執行該文件從而找到XXX庫。其中具體查找庫并給XXX_INCLUDE_DIRSXXX_LIBRARIES兩個變量賦值的操作由XXXConfig.cmake模塊完成。

兩種模式看起來似乎差不多,不過cmake默認采取Module模式,如果Module模式未找到庫,才會采取Config模式。如果XXX_DIR路徑下找不到XXXConfig.cmake文件,則會找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。總之,Config模式是一個備選策略。通常,庫安裝時會拷貝一份XXXConfig.cmake到系統目錄中,因此在沒有顯式指定搜索路徑時也可以順利找到。

在我遇到的問題中,由于Caffe安裝時沒有安裝到系統目錄,因此無法自動找到CaffeConfig.cmake,我在CMakeLists.txt最前面添加了一句話之后就可以了。

set(Caffe_DIR /home/wjg/projects/caffe/build)   #添加CaffeConfig.cmake的搜索路徑

find_package(Caffe REQUIRED)

if (NOT Caffe_FOUND)
    message(FATAL_ERROR "Caffe Not Found!")
endif (NOT Caffe_FOUND)

include_directories(${Caffe_INCLUDE_DIRS})

add_executable(useSSD ssd_detect.cpp)
target_link_libraries(useSSD ${Caffe_LIBRARIES})

其實關于find_package還有許多知識點,可惜我也沒能全部掌握。XXXConfig.cmake的默認搜索路徑也不止一個,它們有詳細的優先級順序。對于庫的開發者來說,如何生成FindXXX.cmake或XXXConfig.cmake文件更是一個復雜工程,需要了解更多的知識,希望以后有機會再深入了解。

參考資料

CMake 2.8.10 Documentation

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 摘要:本系列文章主要講解caffe的整個使用流程,適合初級入門caffe,通過學習本篇文章,理清項目訓練、測試流程...
    踩坑第某人閱讀 8,434評論 0 4
  • Question1 :How find_package() works ? 首先明確一點,cmake本身不提供任何...
    江州司馬binbin閱讀 6,027評論 0 3
  • CMake學習 本篇分享一下有關CMake的一些學習心得以及相關使用。 本文目錄如下: [1、CMake介紹] [...
    AlphaGL閱讀 12,284評論 11 79
  • 看了一些漫畫和紀錄片,對 設計 反而有更多的理解了。 立意的出發點,真的是很重要很重要的。然后,只需要自然流露和節...
    Cisa閱讀 187評論 0 3
  • 等著電梯自己關門 從容與急切 修行與不修行 清涼與煩惱 天堂與地獄 其實常常只有 一秒不到的時間 緩一秒 海闊天空...
    扎高拉姆閱讀 196評論 0 0