原文鏈接:
http://www.cnblogs.com/lidabo/p/3974305.html
https://my.oschina.net/u/1046919/blog/477645
一、 基本使用
安裝:下載二進制包後可直接解壓使用
從源碼安裝則執行命令:./bootstrap; make; make install——嘗試執行bootstrap失敗
使用:cmake dir_path,生成工程文件或makefile文件
二、 概念
out-of-source build,與in-source build相對,即將編譯輸出文件與源文件放到不同目錄中;
三、 基本結構
1,依賴CMakeLists.txt文件,項目主目標一個,主目錄中可指定包含的子目錄;
2,在項目CMakeLists.txt中使用project指定項目名稱,add_subdirectory添加子目錄
3,子目錄CMakeLists.txt將從父目錄CMakeLists.txt繼承設置(TBD,待檢驗)
四、 語法
1. #註釋
2. 變量:使用set命令顯式定義及賦值,在非if語句中,使用${}引用,if中直接使用變量名引用;後續的set命令會清理變量原來的值;
3. command (args ...) #命令不分大小寫,參數使用空格分隔,使用雙引號引起參數中空格
4. set(var a;b;c) <=> set(var a b c) #定義變量var並賦值爲a;b;c這樣一個string list
5. Add_executable(${var}) <=> Add_executable(a b c) #變量使用${xxx}引用
6. 條件語句:
if(var) #var 非empty 0 N No OFF FALSE... #非運算使用NOT
…
else()/elseif() … endif(var)
7. 循環語句
Set(VAR a b c)
Foreach(f ${VAR}) …Endforeach(f)
8. 循環語句
WHILE() … ENDWHILE()
五、 內部變量
CMAKE_C_COMPILER:指定C編譯器
CMAKE_CXX_COMPILER:
CMAKE_C_FLAGS:編譯C文件時的選項,如-g;也可以通過add_definitions添加編譯選項
EXECUTABLE_OUTPUT_PATH:可執行文件的存放路徑
LIBRARY_OUTPUT_PATH:庫文件路徑
CMAKE_BUILD_TYPE::build 類型(Debug, Release, ...),CMAKE_BUILD_TYPE=Debug
BUILD_SHARED_LIBS:Switch between shared and static libraries
內置變量的使用:
>> 在CMakeLists.txt中指定,使用set
>> cmake命令中使用,如cmake -DBUILD_SHARED_LIBS=OFF
六、 命令
project (HELLO) #指定項目名稱,生成的VC項目的名稱;
>>使用${HELLO_SOURCE_DIR}表示項目根目錄
include_directories:指定頭文件的搜索路徑,相當於指定gcc的-I參數
>> include_directories (${HELLO_SOURCE_DIR}/Hello) #增加Hello爲include目錄
link_directories:動態鏈接庫或靜態鏈接庫的搜索路徑,相當於gcc的-L參數
>> link_directories (${HELLO_BINARY_DIR}/Hello) #增加Hello爲link目錄
add_subdirectory:包含子目錄
>> add_subdirectory (Hello)
add_executable:編譯可執行程序,指定編譯,好像也可以添加.o文件
>> add_executable (helloDemo demo.cxx demo_b.cxx) #將cxx編譯成可執行文件——
add_definitions:添加編譯參數
>> add_definitions(-DDEBUG)將在gcc命令行添加DEBUG宏定義;
>> add_definitions( “-Wall -ansi –pedantic –g”)
target_link_libraries:添加鏈接庫,相同於指定-l參數
>> target_link_libraries(demo Hello) #將可執行文件與Hello連接成最終文件demo
add_library:
>> add_library(Hello hello.cxx) #將hello.cxx編譯成靜態庫如libHello.a
add_custom_target:
message( status|fatal_error, “message”):
set_target_properties( ... ): lots of properties... OUTPUT_NAME, VERSION, ....
link_libraries( lib1 lib2 ...): All targets link with the same set of libs
project 命令
語句 : project(<projectname> [languageName1 languageName2 … ] )
作用 : 指定項目名
cmake_minimum_required 命令
語句 : cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]] [FATAL_ERROR])
作用 : 指定cmake需要的最小版本
aux_source_directory 命令
語句 : aux_source_directory(<dir> <variable>)
作用 : 獲取指定目錄下的所有文件,保存到variable中,包括 .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp .hxx .in .txx文件
示例 : aux_source_directory(. var)#獲取當前目錄中源文件
add_executable 命令
語句 : add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
作用 : 將指定文件source編譯成可執行文件,命名位name
示例 : add_executable(hello hello.cpp)
add_library 命令
語句 : add_library([STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
作用 : 添加一個名爲<name>的庫文件,指定STATIC,SHARED,或者MODULE參數用來指定要創建的庫的類型。STATIC庫是目標文件的歸檔文件,在鏈接其它目標的時候使用。SHARED庫會被動態鏈接,在運行時被加載。MODULE庫是不會被鏈接到其它目標中的插件,但是可能會在運行時使用dlopen-系列的函數動態鏈接。如果沒有類型被顯式指定,這個選項將會根據變量BUILD_SHARED_LIBS的當前值是否爲真決定是STATIC還是SHARED
示例 : add_library(Lib ${DIR_SRCS})
add_dependencies 命令
語句 : add_dependencies(target-name depend-target1 depend-target2 …)
作用 : 用於指定某個目標(可執行文件或者庫文件)依賴於其他的目標。這裏的目標必須是 add_executable、add_library、add_custom_target 命令創建的目標
add_subdirectory 命令
語句 : add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
作用 : 用於添加一個需要進行構建的子目錄
示例 : add_subdirectory(directory)
target_link_libraries 命令
語句 : target_link_libraries(<target> [item1 [item2 […]]] [[debug|optimized|general] ] …)
作用 : 用於指定 target 需要鏈接 item1 item2 …。這裏 target 必須已經被創建,鏈接的 item 可以是已經存在的 target(依賴關係會自動添加)
示例 : target_link_libraries(Main Lib)
set 命令
語句 : set(<variable> <value> [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE])
作用 : 用於設定變量 variable 的值爲 value。variable可以自己定義
示例 : set(var "${list}_exe")
unset 命令
語句 : unset(<variable> [CACHE])
作用 : 用於移除變量 variable。如果指定了 CACHE 變量將被從 Cache 中移除。
示例 : unset(VAR CACHE)
message 命令
語句 : message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] “message to display” …)
作用 : 輸出信息
示例 : message("hello world")
include_directories 命令
語句 : include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
作用 : 用於設定目錄,這些設定的目錄將被編譯器用來查找 include 文件
示例 : include_directories(${PROJECT_SOURCE_DIR}/lib)
find_path 命令
語句 : find_path(<VAR> name1 [path1 path2 …])
作用 : 用於查找包含文件 name1 的路徑,如果找到則將路徑保存在 VAR 中(此路徑爲一個絕對路徑),如果沒有找到則結果爲 <VAR>-NOTFOUND。默認的情況下,VAR 會被保存在 Cache 中,這時候我們需要清除 VAR 纔可以進行下一次查詢(使用 unset 命令)
add_definitions 命令
語句 : find_library(<VAR> name1 [path1 path2 …])
作用 : 用於添加編譯器命令行標誌(選項),通常的情況下我們使用其來添加預處理器定義
示例 : add_definitions(-D_UNICODE -DUNICODE)
execute_process 命令
語句 : execute_process(COMMAND <cmd1> [args1...]] [COMMAND <cmd2> [args2...] [...]]
[WORKING_DIRECTORY <directory>]
[TIMEOUT <seconds>]
[RESULT_VARIABLE <variable>]
[OUTPUT_VARIABLE <variable>]
[ERROR_VARIABLE <variable>]
[INPUT_FILE <file>]
[OUTPUT_FILE <file>]
[ERROR_FILE <file>]
[OUTPUT_QUIET]
[ERROR_QUIET]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE])
作用 : 用於執行一個或者多個外部命令。每一個命令的標準輸出通過管道轉爲下一個命令的標準輸入。WORKING_DIRECTORY 用於指定外部命令的工作目錄,RESULT_VARIABLE 用於指定一個變量保存外部命令執行的結果,這個結果可能是最後一個執行的外部命令的退出碼或者是一個描述錯誤條件的字符串,OUTPUT_VARIABLE 或者 ERROR_VARIABLE 用於指定一個變量保存標準輸出或者標準錯誤,OUTPUT_QUIET 或者 ERROR_QUIET 用於忽略標準輸出和標準錯誤。
示例 : execute_process(COMMAND ls)
file 命令
語句 : file(WRITE filename "message to write"... )
作用 : WRITE選項將會寫一條消息到名爲filename的文件中。如果文件已經存在,該命令會覆蓋已有的文件;如果文件不存在,它將創建該文件。
===========================================================
語句 : file(APPEND filename "message to write"... )
作用 : APPEND選項和WRITE選項一樣,將會寫一條消息到名爲filename的文件中,只是該消息會附加到文件末尾。
===========================================================
語句 : file(READ filename variable [LIMIT numBytes] [OFFSET offset] [HEX])
作用 : READ選項將會讀一個文件中的內容並將其存儲在變量裏。讀文件的位置從offset開始,最多讀numBytes個字節。如果指定了HEX參數,二進制代碼將會轉換爲十六進制表達方式,並存儲在變量裏。
===========================================================
語句 : file(STRINGS filename variable [LIMIT_COUNT num] [LIMIT_INPUT numBytes] [LIMIT_OUTPUT numBytes]
[LENGTH_MINIMUM numBytes] [LENGTH_MAXIMUM numBytes]
[NEWLINE_CONSUME] [REGEX regex] [NO_HEX_CONVERSION])
作用 : STRINGS將會從一個文件中將一個ASCII字符串的list解析出來,然後存儲在variable變量中。文件中的二進制數據會被忽略。回車換行符會被忽略。它也可以用在Intel的Hex和Motorola的S-記錄文件;讀取它們時,它們會被自動轉換爲二進制格式。可以使用NO_HEX_CONVERSION選項禁止這項功能。LIMIT_COUNT選項設定了返回的字符串的最大數量。LIMIT_INPUT設置了從輸入文件中讀取的最大字節數。LIMIT_OUTPUT設置了在輸出變量中存儲的最大字節數。LENGTH_MINIMUM設置了要返回的字符串的最小長度;小於該長度的字符串會被忽略。LENGTH_MAXIMUM設置了返回字符串的最大長度;更長的字符串會被分割成不長於最大長度的字符串。NEWLINE_CONSUME選項允許新行被包含到字符串中,而不是終止它們。REGEX選項指定了一個待返回的字符串必須滿足的正則表達式。
===========================================================
語句 : file(GLOB variable [RELATIVE path] [globbing expressions]...)
作用 : GLOB選項將會爲所有匹配查詢表達式的文件生成一個文件list,並將該list存儲進變量variable裏。文件名查詢表達式與正則表達式類似,只不過更加簡單。如果爲一個表達式指定了RELATIVE標誌,返回的結果將會是相對於給定路徑的相對路徑。
===========================================================
語句 : file(GLOB_RECURSE variable [RELATIVE path] [FOLLOW_SYMLINKS] [globbing expressions]...)
作用 : GLOB_RECURSE選項將會生成一個類似於通常的GLOB選項的list,只是它會尋訪所有那些匹配目錄的子路徑並同時匹配查詢表達式的文件。作爲符號鏈接的子路徑只有在給定FOLLOW_SYMLINKS選項或者cmake策略CMP0009被設置爲NEW時,纔會被尋訪到。參見cmake --help-policy CMP0009 查詢跟多有用的信息。
===========================================================
語句 : file(RENAME <oldname> <newname>)
作用 : RENAME選項對同一個文件系統下的一個文件或目錄重命名。
===========================================================
語句 : file(REMOVE [file1 ...])
作用 : REMOVE選項將會刪除指定的文件,包括在子路徑下的文件。
===========================================================
語句 : file(REMOVE_RECURSE [file1 ...])
作用 : REMOVE_RECURSE選項會刪除給定的文件以及目錄,包括非空目錄。
===========================================================
語句 : file(MAKE_DIRECTORY [directory1 directory2 ...])
作用 : MAKE_DIRECTORY選項將會創建指定的目錄,如果它們的父目錄不存在時,同樣也會創建。(類似於mkdir命令——譯註)
===========================================================
語句 : file(RELATIVE_PATH variable directory file)
作用 : RELATIVE_PATH選項會確定從direcroty參數到指定文件的相對路徑。
===========================================================
語句 : file(TO_CMAKE_PATH path result)
作用 : TO_CMAKE_PATH選項會把path轉換爲一個以unix的 / 開頭的cmake風格的路徑。輸入可以是一個單一的路徑,也可以是一個系統路徑,比如"$ENV{PATH}"。注意,在調用TO_CMAKE_PATH的ENV周圍的雙引號只能有一個參數(Note the double quotes around the ENV call TO_CMAKE_PATH only takes one argument. 原文如此。
===========================================================
語句 : file(TO_NATIVE_PATH path result)
作用 : TO_NATIVE_PATH選項與TO_CMAKE_PATH選項很相似,但是它會把cmake風格的路徑轉換爲本地路徑風格:windows下用\,而unix下用/。
===========================================================
語句 : file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log] [EXPECTED_MD5 sum] [SHOW_PROGRESS])
作用 : DOWNLOAD 將給定的URL下載到指定的文件中。如果指定了LOG var選項,下載日誌將會被輸出到var中。如果指定了STATUS var選項,下載操作的狀態會被輸出到var中。該狀態返回值是一個長度爲2的list。list的第一個元素是操作的數字返回值,第二個返回值是錯誤的字符串值。錯誤信息如果是數字0,操作中沒有發生錯誤。如果指定了TIMEOUT time選項,在time秒之後,操作會超時退出;time應該是整數。如果指定了EXPECTED_MD5 sum選項,下載操作會認證下載的文件的實際MD5和是否與期望值匹配。如果不匹配,操作將返回一個錯誤。如果指定了SHOW_PROGRESS選項,進度信息會以狀態信息的形式被打印出來,直到操作完成。
cmake 常用語句
條件控制
======================
if(expression)
# ...
elseif(expression2)
# ...
else()
# ...
endif()
======================
對於 if(string) 來說:
-
如果 string 爲(不區分大小寫)1、ON、YES、TRUE、Y、非 0 的數則表示真
-
如果 string 爲(不區分大小寫)0、OFF、NO、FALSE、N、IGNORE、空字符串、以 -NOTFOUND 結尾的字符串則表示假
-
如果 string 不符合上面兩種情況,則 string 被認爲是一個變量的名字。變量的值爲第二條所述的各值則表示假,否則表示真
===========================================================
if中的語句:
-
if(NOT expression)
爲真的前提是 expression 爲假 -
if(expr1 AND expr2)
爲真的前提是 expr1 和 expr2 都爲真 -
if(expr1 OR expr2)
爲真的前提是 expr1 或者 expr2 爲真 -
if(COMMAND command-name)
爲真的前提是存在 command-name 命令、宏或函數且能夠被調用 -
if(EXISTS name)
爲真的前提是存在 name 的文件或者目錄(應該使用絕對路徑) -
if(file1 IS_NEWER_THAN file2)
爲真的前提是 file1 比 file2 新或者 file1、file2 中有一個文件不存在(應該使用絕對路徑) -
if(IS_DIRECTORY directory-name)
爲真的前提是 directory-name 表示的是一個目錄(應該使用絕對路徑) -
if(variable|string MATCHES regex)
爲真的前提是變量值或者字符串匹配 regex 正則表達式 -
if(variable|string LESS variable|string)
if(variable|string GREATER variable|string)
if(variable|string EQUAL variable|string)
爲真的前提是變量值或者字符串爲有效的數字且滿足小於(大於、等於)的條件 -
if(variable|string STRLESS variable|string)
if(variable|string STRGREATER variable|string)
if(variable|string STREQUAL variable|string)
爲真的前提是變量值或者字符串以字典序滿足小於(大於、等於)的條件 -
if(DEFINED variable)
爲真的前提是 variable 表示的變量被定義了
循環結構
foreach循環
======================
set(VAR a b c)
foreach(f ${VAR})
message(${f})
endforeach()
======================
while循環
======================
set(VAR 5)
while(${VAR} GREATER 0)
message(${VAR})
math(EXPR VAR "${VAR} - 1")
endwhile()
======================
宏定義
macro循環
======================
# 定義一個宏 hello
macro(hello MESSAGE)
message(${MESSAGE})
endmacro()
# 調用宏 hello
hello("hello world")
# 定義一個函數 hello
function(hello MESSAGE)
message(${MESSAGE})
endfunction()
======================
函數定義
======================
function(get_func RESULT)
# RESULT 的值爲實參的值,因此需要使用 ${RESULT}
# 這裏使用 PARENT_SCOPE 是因爲函數會構建一個局部作用域
set(${RESULT} "Hello Function" PARENT_SCOPE)
endfunction()
macro(get_macro RESULT)
set(${RESULT} "Hello Macro")
endmacro()
get_func(V1)
# 輸出 Hello Function
message(${V1})
get_macro(V2)
# 輸出 Hello Macro
message(${V2})
======================
字符串控制
string(REGEX MATCH (regular_expression) (output variable) (input) [(input)...])
string(REGEX MATCHALL (regular_expression) (output variable) (input) [(input)...])
string(REGEX REPLACE (regular_expression) (replace_expression) (output variable) (input) [(input)...])
string(REPLACE (match_string) (replace_string) (output variable) (input) [(input)...])
string(COMPARE EQUAL (string1) (string2) (output variable))
string(COMPARE NOTEQUAL (string1) (string2) (output variable))
string(COMPARE LESS (string1) (string2) (output variable))
string(COMPARE GREATER (string1) (string2) (output variable))
string(ASCII (number) [(number) ...] (output variable))
string(CONFIGURE (string1) (output variable) [@ONLY] [ESCAPE_QUOTES])
string(TOUPPER (string1) (output variable))
string(TOLOWER (string1) (output variable))
string(LENGTH (string) (output variable))
string(SUBSTRING (string) (begin) (length) (output variable))
string(STRIP (string) (output variable))
string(RANDOM [LENGTH (length)] [ALPHABET (alphabet)] (output variable))
cmake 常用變量
-
UNIX 如果爲真,表示爲 UNIX-like 的系統,包括 Apple OS X 和 CygWin
-
WIN32 如果爲真,表示爲 Windows 系統,包括 CygWin
-
APPLE 如果爲真,表示爲 Apple 系統
-
CMAKE_SIZEOF_VOID_P 表示 void* 的大小(例如爲 4 或者 8),可以使用其來判斷當前構建爲 32 位還是 64 位
-
CMAKE_CURRENT_LIST_DIR 表示正在處理的 CMakeLists.txt 文件的所在的目錄的絕對路徑(2.8.3 以及以後版本才支持)
-
CMAKE_ARCHIVE_OUTPUT_DIRECTORY 用於設置 ARCHIVE 目標的輸出路徑
-
CMAKE_LIBRARY_OUTPUT_DIRECTORY 用於設置 LIBRARY 目標的輸出路徑
-
CMAKE_RUNTIME_OUTPUT_DIRECTORY 用於設置 RUNTIME 目標的輸出路徑
七、 說明
1,CMAKE生成的makefile能夠處理好.h文件更改時只編譯需要的cpp文件;
八、 FAQ
1) 怎樣獲得一個目錄下的所有源文件
>> aux_source_directory(<dir> <variable>)
>> 將dir中所有源文件(不包括頭文件)保存到變量variable中,然後可以add_executable (ss7gw ${variable})這樣使用。
2) 怎樣指定項目編譯目標
>> project命令指定
3) 怎樣添加動態庫和靜態庫
>> target_link_libraries命令添加即可
4) 怎樣在執行CMAKE時打印消息
>> message([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)
>> 注意大小寫
5) 怎樣指定頭文件與庫文件路徑
>> include_directories與link_directories
>>可以多次調用以設置多個路徑
>> link_directories僅對其後面的targets起作用
6) 怎樣區分debug、release版本
>>建立debug/release兩目錄,分別在其中執行cmake -DCMAKE_BUILD_TYPE=Debug(或Release),需要編譯不同版本時進入不同目錄執行make即可;
Debug版會使用參數-g;Release版使用-O3 –DNDEBUG
>> 另一種設置方法——例如DEBUG版設置編譯參數DDEBUG
IF(DEBUG_mode)
add_definitions(-DDEBUG)
ENDIF()
在執行cmake時增加參數即可,例如cmake -D DEBUG_mode=ON
7) 怎樣設置條件編譯
例如debug版設置編譯選項DEBUG,並且更改不應改變CMakelist.txt
>> 使用option command,eg:
option(DEBUG_mode "ON for debug or OFF for release" ON)
IF(DEBUG_mode)
add_definitions(-DDEBUG)
ENDIF()
>> 使其生效的方法:首先cmake生成makefile,然後make edit_cache編輯編譯選項;Linux下會打開一個文本框,可以更改,該完後再make生成目標文件——emacs不支持make edit_cache;
>> 侷限:這種方法不能直接設置生成的makefile,而是必須使用命令在make前設置參數;對於debug、release版本,相當於需要兩個目錄,分別先cmake一次,然後分別make edit_cache一次;
>> 期望的效果:在執行cmake時直接通過參數指定一個開關項,生成相應的makefile——可以這樣做,例如cmake –DDEBUGVERSION=ON
8) 怎樣添加編譯宏定義
>> 使用add_definitions命令,見命令部分說明
9) 怎樣添加編譯依賴項
用於確保編譯目標項目前依賴項必須先構建好
>>add_dependencies
10) 怎樣指定目標文件目錄
>> 建立一個新的目錄,在該目錄中執行cmake生成Makefile文件,這樣編譯結果會保存在該目錄——類似
>> SET_TARGET_PROPERTIES(ss7gw PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${BIN_DIR}")
11) 很多文件夾,難道需要把每個文件夾編譯成一個庫文件?
>> 可以不在子目錄中使用CMakeList.txt,直接在上層目錄中指定子目錄
12) 怎樣設定依賴的cmake版本
>>cmake_minimum_required(VERSION 2.6)
13) 相對路徑怎麼指定
>> ${projectname_SOURCE_DIR}表示根源文件目錄,${ projectname _BINARY_DIR}表示根二進制文件目錄?
14) 怎樣設置編譯中間文件的目錄
>> TBD
15) 怎樣在IF語句中使用字串或數字比較
>>數字比較LESS、GREATER、EQUAL,字串比STRLESS、STRGREATER、STREQUAL,
>> Eg:
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
set(AAA abc)
IF(AAA STREQUAL abc)
message(STATUS "true") #應該打印true
ENDIF()
16) 更改h文件時是否只編譯必須的cpp文件
>> 是
17) 機器上安裝了VC7和VC8,CMAKE會自動搜索編譯器,但是怎樣指定某個版本?
>> TBD
18) 怎樣根據OS指定編譯選項
>> IF( APPLE ); IF( UNIX ); IF( WIN32 )
19) 能否自動執行某些編譯前、後命令?
>> 可以,TBD
20) 怎樣打印make的輸出
make VERBOSE=1
參考文獻:
[1] CMake_Tutorial.pdf
[2] CMake使用總結,http://blog.csdn.net/keensword007/archive/2008/07/16/2663235.aspx
[4] 安裝包中文檔
[5] Andrej Cedilnik,HOWTO: Cross-Platform Software Development Using CMake,October, 2003
[6] Cjacker,CMake實踐.PDF