【cmake系列使用教程】
這個系列的文章翻譯自官方cmake教程:cmake tutorial。
示例程式地址:github.com/rangaofei/t…
不會僅僅停留在官方教程。本人作為一個安卓開發者,實在是沒有linux c程式開發經驗,望大佬們海涵。教程是在macos下完成,大部分linux我也測試過,有特殊說明的我會標註出來。本教程基於cmake-3.10.2,同時認為你已經安裝好cmake。
流程判斷
cmake中的流程判斷相對簡單,與c語言接近。
形式如下:
if(expression)
# then section.
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
#...
elseif(expression2)
# elseif section.
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
#...
else(expression)
# else section.
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
#...
endif(expression)
複製程式碼
此處有一點注意:else和endif中的表示式是可以省略的,看到現在大部分網上的教程有必須加SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
這句才能省略表示式,一臉懵逼,關於那個變數,我也查不到api,包括廢棄的,所以我都不寫這句。
if表示式可以用長表示式,優先順序順序如下:
> EXISTS, COMMAND, DEFINED
> EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL, STREQUAL, STRLESS, STRLESS_EQUAL, STRGREATER, STRGREATER_EQUAL, VERSION_EQUAL, VERSION_LESS, VERSION_LESS_EQUAL, VERSION_GREATER, VERSION_GREATER_EQUAL, MATCHES
> NOT,AND,OR
複製程式碼
別看下面這張表很長,其實沒什麼內容:
表示式 | true | false | 說明 |
---|---|---|---|
<constant> | 1, ON, YES, TRUE, Y,或者是非0數字 | 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND,空字串,或者帶-NOTFOUND字尾 | 布林判斷值大小寫不敏感 |
<variable|string> | 已經定義且不是false的變數 | 未定義或者是false的變數 | 變數就是字串 |
<NOT expression> | expression為false | expression為true | |
AND | 兩個條件全部成立 | 至少有一個為假 | |
COMAND command-name | 已經定義的command,macro或者function | 未定義 | |
POLICY policy-id | policy存在 | policy不存在 | 形式為CMP |
TARGET target-name | 已經用add_executable(), add_library(), or add_custom_target()定義過的target | 未定義 | |
TEST test-name | add_test()建立過的測試名稱 | 未建立 | |
EXISTS path-to-file-or-directory | 檔案或者路徑存在 | 檔案或者路徑不存在 | 此處是全路徑 |
file1 IS_NEWER_THAN file2 | file1的時間戳大於file2的時間戳 其中一個檔案不存在 兩個檔案時間戳相同 |
其他情況 | 檔案路徑必須是全路徑 |
IS_DIRECTORY path-to-directory | 給定的變數是資料夾 | 不是資料夾 | 全路徑 |
IS_SYMLINK file-name | 變數是連結 | 不是 | 全路徑 |
IS_ABSOLUTE path | 是絕對路徑 | 不是 | |
<variable|string> MATCHES regex | 正規表示式匹配成功 | 匹配失敗 | |
<variable|string> LESS <variable|string> | 給定的變數是數字並且左邊小於右邊 | 左邊大於右邊 | 用於比較數字的大小 LESS:小於 GREATER:大於 EQUAL:等於 GREATER_EQUAL:大於等於 LESS_EQUAL:小於等於 |
<variable|string> STRLESS <variable|string> | 按字典順序左邊小於右邊 | 左邊大於右邊 | 用於比較字串 LESS:小於 STRGREATER:大於 STREQUAL:等於 STRLESS_EQUAL:小於等於 STRGREATER_EQUAL:大於等於 |
<variable|string> VERSION_LESS <variable|string> | 左邊的版本號小於右邊的版本號 | 大於 | 用於版本號的比較 LESS:小於 VERSION_GREATER:大於 VERSION_EQUAL:等於 VERSION_LESS_EQUAL:小於等於 VERSION_GREATER_EQUAL:大於等於 |
<variable | string> IN_LIST | 右邊的item中有左邊 | 沒有 |
DEFINED | 已定義變數 | 未定義變數 | |
(expr1) AND (expr2 OR (expr3)) | 1為真且2或者3至少有一個為真 | 其他情況 |
在if條件表示式中,是不必用${var}
來取變數的值的,系統會自動轉換。例如設定兩個變數,然後比較各種取值的情況:
set(var1 OFF)
set(var2 "var1")
複製程式碼
if(var2)
實際是判斷var1是否為false;
if(${var2})
相當於if(var1)
,實際是判斷OFF;
foreach迴圈
1. 第一種形式
foreach(loop_var arg1 arg2 ...)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endforeach(loop_var)
複製程式碼
此處注意endforeach(loop_var)
的變數最好不要省略,因為foreach迴圈是依靠變數來跳出迴圈的。
在foreach
和匹配endforeach
之間的所有命令都會被系統記錄而不被呼叫。 一旦找到了了endforeach
,則會執行原來記錄的命令。在迴圈的每次迭代之前,${loop_var}
將被設定為具有列表中當前值的變數。
foreach(i 0 1 2 3)
message(STATUS "current is ${i}")
endforeach(i)
message(STATUS "end")
endforeach(i)
複製程式碼
一個簡單的迴圈,但是多了一個endforeach
。看一下結果
➜ StepTest git:(master) ✗ cmake -P foreach.cmake
-- current is 0
-- current is 1
-- current is 2
-- current is 3
-- end
CMake Error at foreach.cmake:5 (endforeach):
endforeach An ENDFOREACH command was found outside of a proper FOREACH
ENDFOREACH structure. Or its arguments did not match the opening FOREACH
command.
複製程式碼
報錯了。沒有匹配的foreach。
2. 第二種形式
foreach(loop_var RANGE total)
複製程式碼
從0開始直到total
結束(包含total)
foreach(i RANGE 3)
message(STATUS "current is ${i}")
endforeach(i)
複製程式碼
範圍將會是0-3,檢視一下結果:
➜ StepTest git:(master) ✗ cmake -P foreach.cmake
-- current is 0
-- current is 1
-- current is 2
-- current is 3
複製程式碼
3. 第三種形式
foreach(loop_var RANGE start stop [step])
複製程式碼
從start開始直到stop結束之間的值,可以設定步進值step。
foreach(i RANGE 0 3 1)
message(STATUS "current is ${i}")
endforeach(i)
複製程式碼
輸出結果和上面的一樣.
注意一點:最後的結果不會大於stop值,步進值是浮點數時會被轉為整形
4. 第四種形式
foreach(loop_var IN [LISTS [list1 [...]]]
[ITEMS [item1 [...]]])
複製程式碼
也比較簡單,多了LIST關鍵字來迴圈list。不多講。
while迴圈
while(condition)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endwhile(condition)
複製程式碼
注意endwhile中的條件最好不要省略。這個條件和if中的表示式是一樣的規則。 迴圈形式和foreach迴圈類似,直到碰到endwhile才開始執行每一條指令。
在while和foreach迴圈中,取變數的值請用
${var}
。break和continue的用法基本與c一樣,放心使用。
在實際專案中,經常使用option
來和if
搭配。
option使用比較簡單:
option(<option_variable> "help string describing option"
[initial value])
複製程式碼
initial value只能使用ON或者OFF,假如未設定,預設為false。
cmake_dependent_option
是cmake內建的一個module,用來生成依賴其他option
的option,這個相當蛋疼。
看一個簡單的例子:
include(${CMAKE_ROOT}/Modules/CMakeDependentOption.cmake)
option(USE_CURL "use libcurl" ON)
option(USE_MATH "use libm" ON)
cmake_dependent_option(DEPENT_USE_CURL "this is dependent on USE_CURL" ON "USE_CURL;NOT USE_MATH" OFF)
if(DEPENT_USE_CURL)
message(STATUS "using lib curl")
else()
message(STATUS "not using lib curl")
endif()
複製程式碼
第一行包含了我們需要的依賴模組。
第二行第三行定義了兩個option
,USE_CURL
,USE_MATH
全為ON
。
第四行定義了一個option
,DEPENT_USE_CURL
,後邊緊跟的是它的說明
this is dependent on USE_CURL
,再後邊相當於一個三元判斷式,假如USE_CURL;NOT USE_MATH
為真時,取前邊的值,否則取後邊的值。
5-9行是一個if語句,用來輸出我們想要的結果。
輸出結果:
➜ StepTest git:(master) ✗ cmake -P optionc.cmake
-- not using lib curl
複製程式碼