cmake使用教程(七)-流程和迴圈

saka發表於2018-02-16

【cmake系列使用教程】

cmake使用教程(一)-起步

cmake使用教程(二)-新增庫

cmake使用教程(三)-安裝、測試、系統自檢

cmake使用教程(四)-檔案生成器

cmake使用教程(五)-cpack生成安裝包

cmake使用教程(六)-蛋疼的語法

cmake使用教程(七)-流程和迴圈

cmake使用教程(八)-macro和function

這個系列的文章翻譯自官方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()
複製程式碼

第一行包含了我們需要的依賴模組。

第二行第三行定義了兩個optionUSE_CURL,USE_MATH全為ON

第四行定義了一個optionDEPENT_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
複製程式碼

相關文章