1. 程式人生 > >CMake之find_package

CMake之find_package

首先強烈推薦對CMake不熟的同學先看這本書《Cmake實踐》。

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_DIRS和Caffe_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_DIRS和XXX_LIBRARIES兩個變數賦值的操作由FindXXX.cmake模組完成。
Config模式:搜尋XXX_DIR指定路徑下的XXXConfig.cmake檔案,執行該檔案從而找到XXX庫。其中具體查詢庫並給XXX_INCLUDE_DIRS和XXX_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檔案更是一個複雜工程,需要了解更多的知識,希望以後有機會再深入瞭解。

作者:金戈大王
連結:https://www.jianshu.com/p/46e9b8a6cb6a
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。