向 C/C++ 編譯器添加 -D 定義,好比 在CMakeList.txt文件中添加:express
ADD_DEFINITIONS(-DENABLE_DEBUG -DABC) #參數之間用空格分割。
代碼中有:windows
#ifdef ENABLE_DEBUG ... //代碼段生效 #endif
若是要添加其餘的編譯器開關,能夠經過 CMAKE_C_FLAGS 變量和 CMAKE_CXX_FLAGS 變量設置。less
定義 target 依賴的其餘 target ,確保在編譯本 target 以前,其餘的 target 已經被構建。ide
ADD_DEPENDENCIES(target-name depend-target1 depend-target2 ...)
前面已經介紹過了,這裏再也不羅唆。函數
ENABLE_TESTING
指令用來控制 Makefile 是否構建 test 目標,涉及工程全部目錄。語法很簡單,沒有任何參數, ENABLE_TESTING() ,通常狀況這個指令放在工程的主CMakeLists.txt 中 .oop
ADD_TEST 測試
ADD_TEST(testname Exename arg1 arg2 ...)
ADD_TEST(mytest ${PROJECT_BINARY_DIR}/bin/main) ENABLE_TESTING()
生成 Makefile 後,就能夠運行 make test 來執行測試了。ui
基本語法是:spa
AUX_SOURCE_DIRECTORY(dir VARIABLE)
做用是發現一個目錄下全部的源代碼文件並將列表存儲在一個變量中,這個指令臨時被用來自動構建源文件列表。由於目前 cmake 還不能自動發現新添加的源文件。
好比code
AUX_SOURCE_DIRECTORY(. SRC_LIST) ADD_EXECUTABLE(main ${SRC_LIST})
其語法爲
CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])
好比
CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)
若是 cmake 版本小與 2.5 ,則出現嚴重錯誤,整個過程當中止。
在 CMakeLists.txt 處理過程當中執行命令,並不會在生成的 Makefile 中執行。具體語法爲:
EXEC_PROGRAM(Executable [directory in which to run] [ARGS <arguments to executable>] [OUTPUT_VARIABLE <var>] [RETURN_VALUE <var>])
用於在指定的目錄運行某個程序,經過 ARGS 添加參數,若是要獲取輸出和返回值,可經過OUTPUT_VARIABLE 和 RETURN_VALUE 分別定義兩個變量 .
這個指令能夠幫助你在 CMakeLists.txt 處理過程當中支持任何命令,好比根據系統狀況去修改代碼文件等等。
舉個簡單的栗子,咱們要在 src 目錄執行 ls 命令,並把結果和返回值存下來。
能夠直接在 src/CMakeLists.txt 中添加:
EXEC_PROGRAM(ls ARGS "*.c" OUTPUT_VARIABLE LS_OUTPUT RETURN_VALUE LS_RVALUE) IF(not LS_RVALUE) MESSAGE(STATUS "ls result: " ${LS_OUTPUT}) ENDIF(not LS_RVALUE)
在 cmake 生成 Makefile 的過程當中,就會執行 ls 命令,若是返回 0 ,則說明成功執行,
那麼就輸出 ls *.c 的結果。關於 IF 語句,後面的控制指令會提到。
文件操做指令,基本語法爲 :
FILE(WRITE filename "message to write"... ) FILE(APPEND filename "message to write"... ) FILE(READ filename variable) FILE(GLOB variable [RELATIVE path] [globbingexpressions]...) FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expressions]...) FILE(REMOVE [directory]...) FILE(REMOVE_RECURSE [directory]...) FILE(MAKE_DIRECTORY [directory]...) FILE(RELATIVE_PATH variable directory file) FILE(TO_CMAKE_PATH path result) FILE(TO_NATIVE_PATH path result)
這裏的語法都比較簡單,不在展開介紹了。
INCLUDE 指令,用來載入 CMakeLists.txt 文件,也用於載入預約義的 cmake 模塊 .
INCLUDE(file1 [OPTIONAL]) INCLUDE(module [OPTIONAL])
OPTIONAL 參數的做用是文件不存在也不會產生錯誤。
你能夠指定載入一個文件,若是定義的是一個模塊,那麼將在 CMAKE_MODULE_PATH 中搜索這個模塊並載入。
載入的內容將在處理到 INCLUDE 語句是直接執行。
INSTALL 系列指令已經在前面的章節有很是詳細的說明,這裏不在贅述,可參考前面的安裝部分。
FIND_ 系列指令主要包含一下指令:
FIND_FILE(<VAR> name1 path1 path2 ...) #VAR 變量表明找到的文件全路徑,包含文件名 FIND_LIBRARY(<VAR> name1 path1 path2 ...) #VAR 變量表示找到的庫全路徑,包含庫文件名 FIND_PATH(<VAR> name1 path1 path2 ...) #VAR 變量表明包含這個文件的路徑。 FIND_PROGRAM(<VAR> name1 path1 path2 ...) #VAR 變量表明包含這個程序的全路徑。
FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED|COMPONENTS] [componets...]])
用來調用預約義在 CMAKE_MODULE_PATH 下的 Find
FIND_LIBRARY 示例:
FIND_LIBRARY(libX X11 /usr/lib) IF(NOT libX) MESSAGE(FATAL_ERROR 「libX not found」) ENDIF(NOT libX)
沒有找到libX被付爲libX-NOTFOUND
IF(expression) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ELSE(expression) # ELSE section. COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDIF(expression)
另一個指令是 ELSEIF
IF(expression) # THEN section. COMMAND1(ARGS ...) COMMAND2(ARGS ...) ELSEIF(expression) # THEN section. COMMAND1(ARGS ...) COMMAND2(ARGS ...) ELSEIF(expression) # THEN section. COMMAND1(ARGS ...) COMMAND2(ARGS ...) ENDIF(expression)
整體把握一個原則,凡是出現 IF 的地方必定要有對應的ENDIF。出現 ELSEIF 的地方, ENDIF 是可選的。
IF判斷表達式中經常使用的指令:
命令名 | 變量說明 |
---|---|
NOT | True if the expression is not true |
AND | True if both expressions would be considered true individually |
OR | True if either expression would be considered true individually |
COMMAND | True if the given name is a command, macro or function that can be invoked |
POLICY | True if the given name is an existing policy |
TARGET | True if the given name is an existing logical target name such as those created by the add_executable(), add_library(), or add_custom_target() commands} |
EXISTS | True if the named file or directory exists. Behavior is well-defined only for full paths |
IS_DIRECTORY | True if the given name is a directory. Behavior is well-defined only for full paths |
IS_SYMLINK | True if the given name is a symbolic link. Behavior is well-defined only for full paths |
IS_ABSOLUTE | True if the given path is an absolute path |
MATCHES | if(<variable\|string> MATCHES regex) True if the given string or variable’s value matches the given regular expression |
LESS | True if the given string or variable’s value is a valid number and less than that on the right |
GREATER | True if the given string or variable’s value is a valid number and greater than that on the right |
EQUAL | True if the given string or variable’s value is a valid number and equal to that on the right |
STRLESS | True if the given string or variable’s value is lexicographically less than the string or variable on the right |
STRGREATER | True if the given string or variable’s value is lexicographically greater than the string or variable on the right |
STREQUAL | True if the given string or variable’s value is lexicographically equal to the string or variable on the right |
VERSION_LESS | Component-wise integer version number comparison (version format is major[.minor[.patch[.tweak]]] |
VERSION_EQUAL | Component-wise integer version number comparison (version format is major[.minor[.patch[.tweak]]]) |
VERSION_GREATER | Component-wise integer version number comparison (version format is major[.minor[.patch[.tweak]]]) |
DEFINED | True if the given variable is defined. It does not matter if the variable is true or false just if it has been |
一個小栗子,用來判斷平臺差別:
IF(WIN32) MESSAGE(STATUS 「This is windows.」) # 做一些 Windows 相關的操做 ELSE(WIN32) MESSAGE(STATUS 「This is not windows」) # 做一些非 Windows 相關的操做 ENDIF(WIN32)
這就用到了咱們在「經常使用變量」一節提到的 CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS 開關。
能夠 SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
這時候就能夠寫成 :
IF(WIN32) ELSE() ENDIF()
若是配合 ELSEIF 使用,可能的寫法是這樣 :
IF(WIN32) #do something related to WIN32 ELSEIF(UNIX) #do something related to UNIX ELSEIF(APPLE) #do something related to APPLE ENDIF(WIN32)
WHILE 指令的語法是:
WHILE(condition) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDWHILE(condition)
其真假判斷條件能夠參考 IF 指令。
FOREACH 指令的使用方法有三種形式:
FOREACH(loop_var arg1 arg2 ...) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... ENDFOREACH(loop_var)
像咱們前面使用的 AUX_SOURCE_DIRECTORY 的栗子
AUX_SOURCE_DIRECTORY(. SRC_LIST) FOREACH(F ${SRC_LIST}) MESSAGE(${F}) ENDFOREACH(F)
FOREACH(loop_var RANGE total) ENDFOREACH(loop_var)從 0 到 total 以1爲步進
舉例以下:
FOREACH(VAR RANGE 10) MESSAGE(${VAR}) ENDFOREACH(VAR)
最終獲得的輸出是:
0
1
2
3
4
5
6
7
8
9
10
FOREACH(loop_var RANGE start stop [step]) ENDFOREACH(loop_var)
從 start 開始到 stop 結束,以 step 爲步進,
舉例以下
FOREACH(A RANGE 5 15 3) MESSAGE(${A}) ENDFOREACH(A)
最終獲得的結果是:
5
8
11
14
注:整個FOREACH遇到 ENDFOREACH 指令,整個語句塊纔會獲得真正的執行。
***
宏定義以下:
macro(<name> [arg1 [arg2 [arg3 ...]]]) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... endmacro(<name>)
舉個栗子:
set(var "ABC") macro(Moo arg) message("arg = ${arg}") set(arg "abc") message("# After change the value of arg.") message("arg = ${arg}") endmacro() message("=== Call macro ===") Moo(${var}) #輸出以下: === Call macro === arg = ABC # After change the value of arg. arg = ABC
這裏的宏是作了字符串的替換
function(<name> [arg1 [arg2 [arg3 ...]]]) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... endfunction(<name>)
舉個栗子:
set(var "ABC") function(Foo arg) message("arg = ${arg}") set(arg "abc") message("# After change the value of arg.") message("arg = ${arg}") endfunction() message("=== Call function ===") Foo(${var}) #輸出爲: === Call function === arg = ABC # After change the value of arg. arg = abc
上面的栗子和c語言的值傳函數比較像
set(var "abc") # 定義一個變量var,初值爲abc function(f1 arg) set(${arg} "ABC" PARENT_SCOPE) # ${arg} == var, 因而至關於set(var "ABC" PARENT_SCOPE) endfunction() message("before calling f1, var = ${var}") f1(var) # 若是寫成了f1(${var})會怎樣? message("after calling f1, var = ${var}")
須要注意的兩點:
name | 變量說明 |
---|---|
ARGC | 函數實參的個數 |
ARGV | 全部實參列表 |
ARGN | 全部額外實參列表, 即ARGV去掉函數聲明時顯示指定的實參,剩餘的實參 |
ARGV0 | 函數第1個實參 |
ARGV1 | 函數第2個實參 |
ARGV2 | 函數第3個實參 |
依次類推 | 依次類推 |
使用上面表格裏的幾個隱含參數,經過下面這個例子能夠更好的說明上面兩種傳遞參數的方式,函數內部發生了什麼。
function(print_list arg) message("======= args count : ${ARGC} ======= ") # 實際實參個數 message("======= all args ======= ") # 打印全部參數 foreach(v IN LISTS ARGV) message(${v}) endforeach() message("======= all extra args ======= ") # 打印全部額外參數 foreach(v IN LISTS ARGN) message(${v}) endforeach() message("======= print content of ARGV0 ======= ") # 打印第一個參數裏的全部內容 foreach(v IN LISTS ARGV0) message(${v}) endforeach() endfunction() set(arg hello world) message("------------ calling with qutoes -----------") # 使用引號來調用 print_list("${arg}") message("------------ calling without qutoes -----------") # 不使用引號調用 print_list(${arg}) 輸出爲: ------------ calling with qutoes ----------- ======= args count : 1 ======= ======= all args ======= hello world ======= all extra args ======= ======= print content of ARGV0 ======= hello world ------------ calling without qutoes ----------- ======= args count : 2 ======= ======= all args ======= hello world ======= all extra args ======= world ======= print content of ARGV0 ======= hello
從兩個輸出結果裏能夠看到:
1.使用引號包裹參數時
參數個數:1, 即hello world
額外參數個數: 0
打印第一個參數的內容 = 要打印的列表內容
2.不使用引號包裹參數時
參數個數:2, 分別是 hello 和 world
額外參數個數: 1, world
打印第一個參數的內容 = hello
在不使用括號包裹的狀況下,由於函數只須要一個參數,列表裏除了第一個元素的其它元素被當作額外的參數傳給函數了,當我打印第一個參數的時候,就僅僅把列表的第一個元素打印出來了。
經過這個例子能夠看到,在不使用括號來包裹列表類型的參數做爲函數實參時,列表參數內部的空格(或者分號)會使得這個列表的內容被當作多個參數傳遞給函數。 此外,CMake裏的函數支持遞歸調用。