CMakeLists入門學習筆記
0、前言
因為在使用OPENCV以及caffe的過程中都接觸到了許多關於CMake的使用,於是就想了解一下CMake究竟是怎樣一個東西,有什麼作用。順便做一個學習筆記。 本文參考《CMake Practice》這篇文章完成,旨在指導使用者快速使用CMake,如果需要更詳細的內容,請通讀《CMake Practice》這篇文章。下載路徑:http://sewm.pku.edu.cn/src/paradise/reference/CMake%20Practice.pdf
1、CMake簡介
CMake是一個工程構建工具,能夠自動生產makefile檔案,方便構建編譯檔案,連結庫,安裝檔案等。
cmake 的特點主要有:
1,開放原始碼,使用類 BSD 許可釋出。
cmake基本語法規則: 前面提到過,cmake 其實仍然要使用”cmake 語言和語法”去構建,上面的內容就是所謂的”cmake 語言和語法”,最簡單的語法規則是: 1,變數使用${}方式取值,但是在 IF 控制語句中是直接使用變數名 2,指令(引數 1 引數 2…) 引數使用括弧括起,引數之間使用空格或分號分開。 3,指令是大小寫無關的,引數和變數是大小寫相關的。但,推薦你全部使用大寫指令。
2、CMakeLists.txt檔案分析
每個需要編譯的目錄(子目錄)都要有一個CMakeLists.txt檔案 在工程目錄下的CMakeLists.txt檔案稱作工程CMake檔案,在這個檔案裡需要指出工程名字,需要編譯的子目錄,例如:
{
cmake_minimum_required(VERSION 3.5)
PROJECT(HELLO)
ADD_SUBDIRECTORY(src)
}
注:
- cmake_minimum_required(VERSION 3.5): 功能說明: 規定cmake程式的最低版本。可選
- 如果CMakeLists.txt檔案中使用了一些高版本cmake特有的一些命令的時候,就需要加上這樣一行,提醒使用者升級到該版本之後再執行cmake
-
PROJECT 指令: 功能說明: 宣告一個工程 語法: PROJECT(projectname [CXX] [C] [Java]) 引數說明:
- projectname:定義工程名稱
- [CXX]…:指定工程支援的語言列表,可忽略的,預設表示支援所有語言
這個指令隱式的定義了兩個 cmake 變數: ==_BINARY_DIR== 以及 ==_SOURCE_DIR==。 前者表示編譯輸出的路徑;後者表示工程所在的路徑。
- ADD_SUBDIRECTORY 指令: 功能說明: 新增需要編譯的原始檔的子目錄 語法: ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) 引數說明:
- source_dir:向當前工程新增存放原始檔的子目錄
- [binary_dir]:指定中間二進位制或目標檔案存放的位置
- [EXCLUDE_FROM_ALL]:將該目錄從編譯過程中排除
接下來給出一個在子目錄的CMakeLists.txt檔案
{
INCLUDE_DIRECTORIES(/usr/include/thrift)
SET(SRC_LIST main.cc
rpc/CRMasterCaller.cpp
rpc/CRNode_server.skeleton.cpp
rpc/Schd_constants.cpp
rpc/CRMaster.cpp
rpc/CRNode.cpp
rpc/Schd_types.cpp
task/TaskExecutor.cpp
task/TaskMoniter.cpp
util/Const.cpp
util/Globals.cc
util/utils.cc
util/Properties.cpp
)
ADD_EXECUTABLE(crnode ${SRC_LIST})
LINK_DIRECTORIES(/usr/lib /lib/local/lib)
TARGET_LINK_LIBRARIES(crnode log4cpp thrift)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
INSTALL(TARGETS crnode
RUNTIME DESTINATION bin
)
}
注:
- INCLUDE_DIRECTORIES 指令: 功能說明: 向工程新增多個特定的標頭檔案搜尋路徑 語法: INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 …) 引數說明:
- [AFTER|BEFORE]:控制路徑新增順序,追加or置前
- LINK_DIRECTORIES 指令: 功能說明: 新增非標準的共享庫搜尋路徑 語法: LINK_DIRECTORIES(directory1 directory2 …) 引數說明:
- directory1:要新增的目錄路徑
- TARGET_LINK_LIBRARIES 指令: 功能說明: 來為 target 新增需要連結的共享庫 語法: TARGET_LINK_LIBRARIES(target library1
- SET 指令: 功能說明: 顯式的定義變數 語法: SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]) 引數說明:
- VAR:變數名
- [VALUE]:變數值
- ADD_EXECUTABLE 指令: 功能說明: 新增要執行的編譯命令 語法: ADD_EXECUTABLE(target [Value]) 引數說明:
- target:要編譯輸出目標的名字
- [Value]:需要的原始檔
- MESSAGE 指令: 功能說明: 於向終端輸出使用者定義的資訊 語法: MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] “message to display” …) 引數說明:
- [SEND_ERROR | STATUS | FATAL_ERROR]:產生錯誤,生成過程被跳過 | 輸出字首為—的資訊 | 立即終止所有 cmake 過程
-
INSTALL 指令: 功能說明: 將編譯生成的檔案分類安裝到制定的目錄路徑。可分成好幾類檔案的安裝命令
-
安裝目標檔案 語法:
{ INSTALL(TARGETS targets... [[ARCHIVE|LIBRARY|RUNTIME] [DESTINATION < dir >] [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT < component >] [OPTIONAL] ] [...]) }
舉例說明:
{ INSTALL(TARGETS myrun mylib mystaticlib RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION libstatic) }
上面的例子會將: 將: 1) 可執行二進位制檔案 myrun, 安裝到${CMAKE_INSTALL_PREFIX}/bin 目錄 2) 動態庫 libmylib, 安裝到${CMAKE_INSTALL_PREFIX}/lib 目錄 3) 靜態庫 libmystaticlib, 安裝到${CMAKE_INSTALL_PREFIX}/libstatic 目錄
-
安裝普通檔案 語法:
{ INSTALL(FILES files... DESTINATION <dir> [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [RENAME <name>] [OPTIONAL]) }
舉例說明:
{ INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/t2) }
上面的例子會將: 把檔案COPYRIGHT、README, 安裝到目錄 < prefix >/share/doc/cmake/t2下
-
安裝非目標檔案的可執行程式檔案(指令碼檔案) 語法:
{ INSTALL(PROGRAMS files... DESTINATION <dir> [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [RENAME <name>] [OPTIONAL]) }
舉例說明:
{ INSTALL(PROGRAMS runhello.sh DESTINATION bin) }
上面的例子會將: 把可執行檔案runhello.sh, 安裝到目錄< prefix >/bin下
-
安裝目錄 語法:
{ INSTALL(DIRECTORY dirs... DESTINATION <dir> [FILE_PERMISSIONS permissions...] [DIRECTORY_PERMISSIONS permissions...] [USE_SOURCE_PERMISSIONS] [CONFIGURATIONS [Debug|Release|...]] [COMPONENT <component>] [[PATTERN <pattern> | REGEX <regex>] [EXCLUDE] [PERMISSIONS permissions...]] [...]) }
舉例說明:
{ INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj PATTERN "CVS" EXCLUDE PATTERN "scripts/*" PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ) }
上面的例子會: 將 icons 目錄安裝到 < prefix >/share/myproj 將 scripts/中的內容安裝到/share/myproj 不包含目錄名為 CVS 的目錄 對於 scripts/*檔案指定許可權為 OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ
-
3、內部編譯與外部編譯
假設我們此時已經完成了兩個CMakeLists.txt檔案的編寫,可以執行cmake命令生成Makefile檔案了。此時我們由兩種方法可以執行cmake、編譯和安裝:
cmake .
make
或者
mkdir build
cd build
cmake ..
make
兩種方法最大的不同在於執行cmake和make的工作路徑不同。 第一種方法中,cmake生成的所有中間檔案和可執行檔案都會存放在專案目錄中,稱為“內部構建” 而第二種方法中,中間檔案和可執行檔案都將存放再build目錄中。稱為“外部構建”。 cmake強烈推薦使用外部構建的方法。