CMake 條件判斷


CMake簡介

  • CMake 是做什么的?
    CMake是一套類似於automake的跨平台輔助項目編譯的工具。 我覺得語法更加簡單易用。

  • CMake的工作流程
    CMake處理頂級目錄的CMakeLists.txt(CMake的配置文件,配置了子目錄,編譯目標,編譯依賴等等),最后根據配置生成相應的MakeFile。

    使用make命令既可以進行編譯。

CMake 基本語法

CMake定義了一套領域編程語言或者說腳本,稱為CMake語言,支持變量定義、流程控制、函數、預制函數。

文件組織

CMake能夠處理cmake語言源碼。

在一個項目中,cmake語言源碼存在的位置分為以下兩種。

文件夾 (CMakeLists.txt),
script腳本 (<script>.cmake,后綴不重要)
  • Directories

    在項目中,項目根目錄的CMakeLists.txt是CMake的入口點,也就是說CMake命令先找CMakeL
    ists.txt,並執行內部的命令,生成構建系統。CMakeLists.txt應該定義了所有的編譯控制。
    並用add_subdirectory()指定要處理的子文件夾(子項目),子文件夾內部也要有
    CMakeLists.txt文件,在CMake執行到add_subdirectory()時,CMake會進入到指定的子文
    件夾,然后在子文件夾內部尋找CMakeLists.txt執行,生成子文件夾的構建系統。子文件夾的
    源碼的構建工作目錄就是在子文件夾內。

  • Scripts
    stripts腳本如果要單獨執行,需要cmake -P xxx.cmake。stripts腳本不會生成構建系統,
    因為在stripts腳本中,不允許指定構建目標。

command

CMake代碼由一系列command的調用組成。包括if else 都屬於command。
類似於下面這個命令

\# 添加可執行目標hello, 參數為world.c

add_executable(hello world.c)

command調用語法為

identifier(以空格隔開的參數表)
參數可以用()括起來,表示這個單個參數。
如if(TRUE OR (TRUE AND FALSE))

注意:command名大小寫不敏感

參數類型有

方括號形式

[={len}[

內部隨便寫點文本,cmake不會內部的變量引用或者換行進行處理。可以保持文本原始樣子。${variable}

\-escape

]=]

方括號不允許嵌套

={len}的意思:len表示結束符的=個數。當[=2]時, ]==] 才是結束符。

例子:

message([=3[
This is the first line in a bracket argument with bracket length 1.
No \-escape sequences or ${variable} references are evaluated.
This is always one argument even though it contains a ; character.
The text does not end on a closing bracket of length 0 like ]].
It does end in a closing bracket of length 1.
]===])

引號形式

引號形式的就是放在""內部的參數,""會被當成一個參數傳進函數。""內部的變量引用或者轉義會
被解析。可以用\表示字符串還沒有結束。

message("This is a quoted argument containing multiple lines.
This is always one argument even though it contains a ; character.
Both \\-escape sequences and ${variable} references are evaluated.
The text does not end on an escaped double-quote like \".
It does end in an unescaped double quote.
")

無引號形式

CMake支持參數不帶任何引號,因為所有值都會轉換成String。所有的參數會被封裝成List。
List的分隔符為;,所以參數列表內如果一個字符串用;分割,;兩邊會被當成兩個參數。

\#這里有四個參數
commandName(arg arg2 arg3;arg4)
foreach(arg
    NoSpace
    Escaped\ Space
    This;Divides;Into;Five;Arguments
    Escaped\;Semicolon
    )
  message("${arg}")
endforeach()

輸出

NoSpace
Escaped Space
This
Divides
Into
Five
Arguments
Escaped;Semicolon

注釋

注釋分為行注釋和塊注釋

  • 行注釋

    # 行注釋,只能寫一行內容

  • 塊注釋
    塊注釋有結尾有開頭,可以寫多行注釋。用[[]]括起來,注意[要緊跟#。

    #[[這是多
    行注釋]]

流程控制

條件控制

if(condition)
elseif(condition)
else()
endif()

if(VAR1 MATCHES "Hello")
    message("this is hello")
    message("this is hello2")
elseif(VAR1 MATCHES "world")
    message("this is world")
    message("this is world2")
endif()

循環

for循環

語法為

foreach(loop_var arg1 arg2 ...)
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
  ...
endforeach(loop_var)

示例

set(mylist "a" "b" c "d")
foreach(_var ${mylist})
     message("當前變量是:${_var}")
endforeach()

上面是最簡單的用法,還有一個foreach(loop_var RANGE start stop [step]) 的用法。


set(result 0)
foreach(_var RANGE 0 100)
     math(EXPR result "${result}+${_var}")
endforeach()
message("from 0 plus to 100 is:${result}")

在foreach循環中,支持break()和continue()。

while循環

while(condition)
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
  ...
endwhile(condition)

自定義command

CMake系統內置了一批command,https://cmake.org/cmake/help/v3.7/manual/cmake-commands.7.html
但是開發者仍然能夠自定義command。

function

function(<name> [arg1 [arg2 [arg3 ...]]])
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
  ...
endfunction(<name>)

在function內可以使用一些變量取得傳入的參數信息。

變量名 意義
ARGC 參數個數
ARGV 參數列表
ARGV0 參數0
ARGV1 參數1
ARGV2 參數2
ARGN 超出最后一個預期參數的參數列表

函數原型聲明時,只接受一個參數,那么調用函數時傳遞給函數的參數列表中,
從第二個參數(如果有的話)開始就會保存到ARGN。

例如

function (argument_tester arg)
    message(STATUS "ARGN: ${ARGN}")
    message(STATUS "ARGC: ${ARGC}")
    message(STATUS "ARGV: ${ARGV}")
    message(STATUS "ARGV0: ${ARGV0}")
    message(STATUS "ARGV0: ${arg}")

    list(LENGTH ARGV  argv_len)
    message(STATUS "length of ARGV: ${argv_len}")
    set(i 0)
    while( i LESS ${argv_len})
         list(GET ARGV ${i} argv_value)
         message(STATUS "argv${i}: ${argv_value}")

         math(EXPR i "${i} + 1")
    endwhile()


endfunction ()
argument_tester(arg0 arg1 arg2 arg3)

macro

宏和function的作用是一樣的,但是宏只是對字符串的簡單替換。和define類似。

macro( [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endmacro( )

下面簡單的用一個實例區分兩者的區別

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})

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 macro ===
arg = ABC
\# After change the value of arg.
arg = ABC
=== Call function ===
arg = ABC
\# After change the value of arg.
arg = abc

變量定義和引用

CMake中,變量的值要么是String要么是String組成的List。

CMake沒有用=賦值的操作,只有通過set,option來定義變量。
option只能定義OFF,ON的變量。

變量定義

set

set分為兩種

  • set普通變量
set(<variable> <value>... [PARENT_SCOPE])

例如

//VA=a;b, VA是一個字符串list
set(VA a b)
//VA=a,VA是一個字符串
set(VB a)
  • set CACHE變量
    CACHE變量會自動保存到CMakeCache.txt中,上次的結果下次繼續用。
set(<variable> <value>... CACHE <type> <docstring> [FORCE])

示例

set(ICD_LIBRARY "${PROJECT_BINARY_DIR}/lib" CACHE INTERNAL "ICD Library location" )

option

option(<option_variable> "help string describing option"
       [initial value])

變量引用

可以使用${variable_name} 。如果變量沒有定義,返回空. 變量引用可以嵌套,變量引用的值從內往外計算。

${outer_${inner_variable}_variable}.

CMake系統內置了一堆的變量,可以查閱

https://cmake.org/cmake/help/v3.7/manual/cmake-variables.7.html

環境變量的訪問

$ENV{VAR}

變量只有string類型。變量名字大小寫敏感,並且可以包含任意字符。
采用set()/unset()定義和取消定義

變量作用域存在於set的當前作用域

變量作用域:

  • Function Scope
    在函數內部set的變量,作用域作用於當前函數及其調用的函數內。return 后就沒了。

  • Directory Scope
    再CMakeLists.txt定義的變量(非function內部),作用域在當前Directory及其子Directory中。

  • Persistent Cache
    持久緩存。變量值會緩存到CMakeCache.txt中,下次運行,會使用CMakeCache中的值。

采用set(variable value CACHE <type> "")方式設置。

set(ICD_LIBRARY "${PROJECT_BINARY_DIR}/lib" CACHE INTERNAL "ICD Library location" )

CMake將會自動把find_path和option的值放到CMakeCache中。

Lists

在CMake中,所有的值都會被當成string來存儲,但是在某些情況下, 多個string可以組成list。
例如在無""參數,多個字符串中間加了一個;。可以使用循環來遍歷List

set(srcs a.c b.c c.c) #sets "srcs" to "a.c;b.c;c.c"

CMake專門提供了一個內置command來處理list

list(LENGTH <list> <output variable>) //獲得list長度
list(GET <list> <element index> [<element index> ...]
     <output variable>) //獲得list的某個位置元素
list(APPEND <list> [<element> ...])//add
list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)//清理
list(FIND <list> <value> <output variable>) //查找
list(INSERT <list> <element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value> [<value> ...])
list(REMOVE_AT <list> <index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM