首先強烈推薦對CMake不熟的同學(xué)先看這本書《Cmake實踐》(提取碼:qgca)狰右。
CMake說起來是個好東西,可是真正用的時候并不那么容易舆床,很容易出現(xiàn)各種各樣的錯誤棋蚌。這不,最近就被find_package這個命令折騰得死去活來挨队。只好花了一天半時間附鸽,看上面那本書,再查資料瞒瘸,總算解決了昨天遇到的問題坷备。
問題描述
已經(jīng)成功編譯了深度學(xué)習(xí)框架Caffe,例程也可以順利執(zhí)行情臭。
但是當(dāng)我在自己的代碼中調(diào)用編譯好的Caffe庫時省撑,卻出現(xiàn)了編譯錯誤。此前俯在,我已經(jīng)在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)
執(zhí)行make后竟秫,鏈接出錯,找不到libboost_system.so文件跷乐。
這一錯誤倒是給我提了個醒肥败,我本以為自己的代碼中沒用到boost,就不必添加boost庫路徑了,誰知道libcaffe.so中用到的庫也需要手動添加進去馒稍。
這時候我才意識到動態(tài)鏈接庫和靜態(tài)鏈接庫的區(qū)別皿哨。前者在程序運行時動態(tài)加載,而后者是在編譯時就和程序結(jié)合到一起了纽谒。于是動態(tài)鏈接庫即使編譯完成证膨,也和其它動態(tài)庫是分離的,因此每次用都要把所有涉及的動態(tài)庫全部添加進來鼓黔。在我的例子中央勒,不僅僅需要添加boost,還有atlas澳化、protobuf等等一大堆動態(tài)鏈接庫需要添加崔步。這個時候,一條條添加就顯得太過麻煩缎谷,可以借助find_package命令一次性添加所有與Caffe相關(guān)的動態(tài)鏈接庫井濒。
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纺铭。只不過,庫的作者通常會提供這兩個文件刀疙,以方便使用者調(diào)用舶赔。
find_package采用兩種模式搜索庫:
- Module模式:搜索CMAKE_MODULE_PATH指定路徑下的FindXXX.cmake文件,執(zhí)行該文件從而找到XXX庫谦秧。其中竟纳,具體查找?guī)觳⒔oXXX_INCLUDE_DIRS和XXX_LIBRARIES兩個變量賦值的操作由FindXXX.cmake模塊完成。
- Config模式:搜索XXX_DIR指定路徑下的XXXConfig.cmake文件疚鲤,執(zhí)行該文件從而找到XXX庫锥累。其中具體查找?guī)觳⒔oXXX_INCLUDE_DIRS和XXX_LIBRARIES兩個變量賦值的操作由XXXConfig.cmake模塊完成。
兩種模式看起來似乎差不多集歇,不過cmake默認(rèn)采取Module模式桶略,如果Module模式未找到庫,才會采取Config模式。如果XXX_DIR路徑下找不到XXXConfig.cmake文件际歼,則會找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件惶翻。總之蹬挺,Config模式是一個備選策略维贺。通常,庫安裝時會拷貝一份XXXConfig.cmake到系統(tǒng)目錄中巴帮,因此在沒有顯式指定搜索路徑時也可以順利找到溯泣。
在我遇到的問題中,由于Caffe安裝時沒有安裝到系統(tǒng)目錄榕茧,因此無法自動找到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})
其實關(guān)于find_package還有許多知識點用押,可惜我也沒能全部掌握肢簿。XXXConfig.cmake的默認(rèn)搜索路徑也不止一個,它們有詳細(xì)的優(yōu)先級順序蜻拨。對于庫的開發(fā)者來說池充,如何生成FindXXX.cmake或XXXConfig.cmake文件更是一個復(fù)雜工程,需要了解更多的知識缎讼,希望以后有機會再深入了解收夸。