目錄:
cmake中定義搜索路徑
修改環(huán)境變量增加搜索路徑
FIND 系列指令尚洽,通過FIND尋找路徑并進行添加
大型開源庫路徑添加方式
find_package采用兩種模式搜索庫
路徑搜索,這里介紹頭文件的路徑搜索和庫文件的路徑搜索。
cmake中定義搜索路徑
cmake中定義頭文件的搜索路徑:INCLUDE_DIRECTORIES 命令添加搜索路徑
庫文件的搜索路徑是:LINK_DIRECTORIES 命令添加庫搜索路徑
link_libraries:(添加需要鏈接的庫文件路徑琉历,注意這里是全路徑)俩由,該用法已經(jīng)被廢棄馒索。
為最終目標鏈接庫使用: TARGET_LINK_LIBRARIES 鏈接庫(動態(tài)庫和靜態(tài)庫)
需要鏈接的庫,會根據(jù)系統(tǒng)動態(tài)庫的搜索路徑依次進行搜索铛绰。這里可以直接寫庫的名稱(程序定義路徑,環(huán)境變量定義的路徑产喉,系統(tǒng)默認搜索路徑)
target_link_libraries 要在 add_executable 之后捂掰,link_libraries 要在 add_executable 之前
修改環(huán)境變量增加搜索路徑
CMAKE_INCLUDE_PATH 和CMAKE_LIBRARY_PATH
特殊的環(huán)境變量CMAKE_INCLUDE_PATH
和 CMAKE_LIBRARY_PATH
務(wù)必注意,這兩個是環(huán)境變量而不是 cmake 變量曾沈。
使用方法是要在 bash 中用 export 或者在 csh 中使用 set 命令設(shè)置或者 CMAKE_INCLUDE_PATH=/home/include cmake ..
等方式这嚣。如果頭文件沒有存放在常規(guī)路徑(/usr/include, /usr/local/include
等), 則可以通過這些變量就行彌補晦譬。
為了將程序更智能一點疤苹,我們可以使用 CMAKE_INCLUDE_PATH
來進行,使用 bash 的方法 如下:
export CMAKE_INCLUDE_PATH=/usr/include/hello
eg:
設(shè)置export CMAKE_INCLUDE_PATH=/usr/include/hello
頭文件中將 INCLUDE_DIRECTORIES(/usr/include/hello)替換為:
FIND_PATH(myHeader hello.h)
IF(myHeader)
INCLUDE_DIRECTORIES(${myHeader})
ENDIF(myHeader)
這里簡單說明一下敛腌,F(xiàn)IND_PATH 用來在指定路徑中搜索文件名卧土,比如:
FIND_PATH(myHeader NAMES hello.h PATHS /usr/include /usr/include/hello)
這里我們沒有指定路徑惫皱,但是,cmake 仍然可以幫我們找到 hello.h 存放的路徑尤莺,就是因為我們設(shè)置了環(huán)境變量 CMAKE_INCLUDE_PATH
旅敷。
如果你不使用 FIND_PATH
,CMAKE_INCLUDE_PATH
變量的設(shè)置是沒有作用的颤霎,你不能指望它會直接為編譯器命令添加參數(shù)-I<CMAKE_INCLUDE_PATH>
媳谁。
以此為例,CMAKE_LIBRARY_PATH
可以用在 FIND_LIBRARY
中友酱。
同樣晴音,因為這些變量直接為 FIND_ 指令所使用,所以所有使用 FIND_ 指令的 cmake 模塊都會受益缔杉。
FIND 系列指令锤躁,通過FIND尋找路徑并進行添加
FIND_系列指令主要包含一下指令:
FIND_FILE(<VAR> name1 path1 path2 ...)
VAR 變量代表找到的文件全路徑,包含文件名
FIND_LIBRARY(<VAR> name1 path1 path2 ...)
VAR 變量表示找到的庫全路徑或详,包含庫文件名
FIND_LIBRARY 示例:
FIND_LIBRARY(libX X11 /usr/lib)
IF(NOT libX)
MESSAGE(FATAL_ERROR “l(fā)ibX not found”)
ENDIF(NOT libX)
FIND_PATH(<VAR> name1 path1 path2 ...)
VAR 變量代表包含這個文件的路徑系羞。
FIND_PROGRAM(<VAR> name1 path1 path2 ...)
VAR 變量代表包含這個程序的全路徑。
FIND_PACKAGE
FIND_PACKAGE(<name> [major.minor]
[QUIET] [NO_MODULE]
[[REQUIRED|COMPONENTS] [componets...]] )
FIND_PACKAGE 其實是系統(tǒng)與定義的cmake模塊霸琴。對于系統(tǒng)預(yù)定義的 Find<name>.cmake 模塊椒振,使用方法一般如上例所示: 每一個模塊都會定義以下幾個變量
- <name>_FOUND
- <name>_INCLUDE_DIR or <name>_INCLUDES
- <name>_LIBRARY or <name>_LIBRARIES
你可以通過<name>_FOUND 來判斷模塊是否被找到,如果沒有找到梧乘,按照工程的需要關(guān)閉 某些特性澎迎、給出提醒或者中止編譯,上面的例子就是報出致命錯誤并終止構(gòu)建宋下。
如果<name>_FOUND 為真嗡善,則將<name>_INCLUDE_DIR 加入 INCLUDE_DIRECTORIES, 將<name>_LIBRARY 加入 TARGET_LINK_LIBRARIES 中学歧。
舉個例子:
FIND_PACKAGE(CURL)
IF(CURL_FOUND)
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(curltest ${CURL_LIBRARY})
ELSE(CURL_FOUND)
MESSAGE(FATAL_ERROR ”CURL library not found”)
ENDIF(CURL_FOUND)
FIND_PACKAGE 其實內(nèi)部主要還是通過FIND_PATH罩引,F(xiàn)IND_LIBRARY等基礎(chǔ)命令實現(xiàn)的。
大型開源庫路徑添加方式
如果是簡單的引入枝笨,可以直接通過指令I(lǐng)NCLUDE_DIRECTORIES袁铐,LINK_DIRECTORIES或者CMAKE_INCLUDE_PATH和CMAKE_LIBRARY_PATH進行設(shè)置。但是該方式存在缺點
- 需要把路徑固定横浑,不宜遷移剔桨,修改麻煩
- 如果存在大量的路徑的話,需要一次添加所有的路徑比較復(fù)雜
因此可以通過FIND 進行查找路徑徙融,通過FIND_PACKAGE 獲得所有的頭文件和庫文件路徑洒缀。
比如對于OpenCV,這樣的方式將會十分方便。這里介紹幾種常用的方式:
- 方式一:FIND_PACKAGE
通過FIND_PACKAGE的方式树绩。
#添加OPENCV庫
#指定OpenCV版本萨脑,代碼如下
#find_package(OpenCV 3.3 REQUIRED)
#如果不需要指定OpenCV版本,代碼如下
find_package(OpenCV REQUIRED)
#添加OpenCV頭文件
include_directories(${OpenCV_INCLUDE_DIRS})
# 添加一個可執(zhí)行程序
# 語法:add_executable( 程序名 源代碼文件 )
add_executable( main main.cpp )
# 將庫文件鏈接到可執(zhí)行程序上
target_link_libraries( main ${OpenCV_LIBS})
要求opencv安裝在系統(tǒng)默認目錄下饺饭。
- 方式二:cmake 關(guān)PKG-CONFIG的指令方式
其實和方式二一樣渤早,但是實現(xiàn)的方式上有出入。通過opencv自帶的pkg-config 提供的opencv.pc文件瘫俊。
# 編譯該工程CMAKE最低版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.2 FATAL_ERROR)
# 工程名字
PROJECT(MAIN)
#通過pkg-config管理的三方庫
# 非root下需要自己加入PKG_CONFIG_PATH鹊杖,不然報錯!!!
SET(ENV{PKG_CONFIG_PATH} /home/topeet/programfile/opencv2/lib/pkgconfig)
#PkgConfig名字是固定的蒋困,代表準備加入pkg-config模塊提茁,即查找/usr/bin/pkg-config
FIND_PACKAGE(PkgConfig REQUIRED)
#通過執(zhí)行pkg-config程序,并指定我需要的模塊是opencv,注意opencv名字固定叉弦,是源于安裝OpenCV生成的opencv.pc胸哥,PKG_OPENCV是前綴(觀察下面)涯竟,
PKG_SEARCH_MODULE(PKG_OPENCV REQUIRED opencv)
# 添加三方opencv的頭文件路徑-- -I/home/topeet/programfile/opencv2/include/opencv -I/home/topeet/programfile/opencv2/include
INCLUDE_DIRECTORIES(${PKG_OPENCV_INCLUDE_DIRS})
# 指定生成目標
ADD_EXECUTABLE(main main.cpp)
# 為指定的bin文件添加三方鏈接庫
TARGET_LINK_LIBRARIES(main detect ${PKG_OPENCV_LDFLAGS})
find_package采用兩種模式搜索庫
Module模式:搜索CMAKE_MODULE_PATH指定路徑下的FindXXX.cmake文件,執(zhí)行該文件從而找到XXX庫空厌。其中,具體查找?guī)觳⒔oXXX_INCLUDE_DIRS和XXX_LIBRARIES兩個變量賦值的操作由FindXXX.cmake模塊完成银酬。
Module 搜素路徑:
- CMAKE_MODULE_PATH指定的路徑
- <CMAKE_ROOT>/share/cmake-x.y/Mdodules (注意:x.y表示版本號嘲更。我的是3.10)。其中CMAKE_ROOT是你在安裝Cmake的時候的系統(tǒng)路徑揩瞪,因為我并沒有指定安裝路徑赋朦,所以是系統(tǒng)默認的路徑,在我的系統(tǒng)中(ubuntu16.04)系統(tǒng)的默認路徑是/usr/loacl李破,如果你在安裝的過程中使用了
cmake -DCMAKE_INSTALL_PREFIX=自己dir路徑 宠哄,那么此時CMAKE_ROOT就代表那個你寫入的路徑 。($CMAKE_ROOT的具體值可以通過CMake中message命令輸出)嗤攻。這稱為模塊模式毛嫉。
Config模式:搜索XXX_DIR指定路徑下的XXXConfig.cmake文件,執(zhí)行該文件從而找到XXX庫妇菱。其中具體查找?guī)觳⒔oXXX_INCLUDE_DIRS和XXX_LIBRARIES兩個變量賦值的操作由XXXConfig.cmake模塊完成承粤。
Config 搜索路徑:
- 搜索xxx_DIR 指定的路徑。如果在CMakeLists.txt中沒有設(shè)置這個cmake變量闯团。也就是說沒有下面的指令:
set(xxx_DIR "xxxConfig.cmkae文件所在的路徑")
那么Cmake就不會搜索xxx_DIR指定的路徑 - Cmake 會在/usr/local/lib/cmake/xxx/ /usr/local/share/xxx 中的xxxConfig.cmake文件辛臊。這個路徑不同的操作系統(tǒng)存在差異。
兩種模式看起來似乎差不多房交,不過cmake默認采取Module模式彻舰,如果Module模式未找到庫,才會采取Config模式。若果在Module的搜索路徑中沒有找到對應(yīng)的cmake file刃唤,則使用config模式隔心。總之透揣,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})