maskmoo 发表于 2024-10-20 21:46

《Cmake构建实战》3 Cmake基础语法学习

本帖最后由 maskmoo 于 2024-10-20 21:45 编辑

<p>第3章主要描述Cmake的基本使用语法,结合书中的实例整理如下</p>

<p><strong>CMake程序</strong></p>

<p>cmake的文件类型包括CMakeList.txt文件和扩展名为.cmake的文件。其中CMakeList.txt是用于组织构建项目源文件的目录结构,.cmake文件可以作为脚本和模块两种类型。</p>

<p>目录(CMakeList.txt) 脚本(&lt;script&gt;.cmake) 模块 (&lt;module&gt;.cmake)<br />
<strong>注释</strong></p>

<p>主要分为单行注释和多行注释,其中多行注释本质上是单行注释+括号参数的组成形式</p>

<pre>
<code class="language-bash">#单行注释

#[=[多行注释 ]=]
</code></pre>

<p><br />
<strong>命令调用</strong></p>

<p>message if for等</p>

<p><br />
<strong>命令参数</strong></p>

<p>引号参数</p>

<pre>
<code>#包含换行
message("CMake
你好!")

#不包含换行

message("\
CMake\
您好!\
")</code></pre>

<p> &nbsp;</p>

<p> &nbsp;</p>

<p>非引号参数&nbsp;</p>

<pre>
<code>message("x;y;z") # 引号参数
message(x y z) # 多个非引号参数
message(x;y;z) # 非引号参数</code></pre>

<p> &nbsp;</p>

<p>变量引用</p>

<pre>
<code>set(var_a 您好)
set(var_b a)

message(${var_${var_b}})</code></pre>

<p> &nbsp;</p>

<p>转义字符&nbsp;</p>

<pre>
<code>cmake_minimum_required(VERSION 3.20)

set("a?b" "变量a?b")

# \? 转义为 ?
message(${a\?b})
message(今天是几号\?)

# \n 转义为换行符,\t 转义为制表符,\! 转义为 !
message(回答:\n\t今天是1号\!)

set("a;b" "变量a;b")

# 非引号参数中 \; 转义为 ;,且不分隔变量
message(x;y\;z)
# 引号参数中 \; 不转义
message("x;y\;z")
# 变量引用中 \; 转义为 ;
message("${a\;b}")
</code></pre>

<p> &nbsp;</p>

<p>括号参数</p>

<pre>
<code>message([==[
abc
def
]==])

message([===[abc
def
]===])

message([===[
随便写终止方括号并不会导致文本结束,
因此右边这两个括号]]也会包括在原始文本中。
下一行中最后的括号也是原始文本的一部分,
因为等号的数量与起始括号不匹配。]==]
]===])</code></pre>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p><strong>变量</strong></p>

<p>预定义变量</p>

<pre>
<code>message("CMake命令行:${CMAKE_COMMAND}")
message("OS:${CMAKE_HOST_SYSTEM_NAME}")</code></pre>

<p> &nbsp;</p>

<p>定义普通变量</p>

<p>需要注意的是变量的作用域</p>

<pre>
<code>function(f)
    set(a "我是修改后的a")
    set(b "我是b")
    set(c "我是c" PARENT_SCOPE)
endfunction()

set(a "我是a")
f()

message("a: ${a}")
message("b: ${b}")
message("c: ${c}")</code></pre>

<p> &nbsp;<br />
缓存变量</p>

<pre>
<code>cmake_minimum_required(VERSION 3.20)
project(Notepad)

set(path_to_notepad "" CACHE FILEPATH "Path to notepad.exe")

# 下面的命令将会用记事本打开同一目录中的in.txt
execute_process(COMMAND "cmd" "/c"
    ${path_to_notepad} ${CMAKE_CURRENT_LIST_DIR}/in.txt)</code></pre>

<p> &nbsp;</p>

<p>环境变量</p>

<pre>
<code>message("main \$ENV{PATH}: $ENV{PATH}")</code></pre>

<p><strong>列表</strong></p>

<p>定义列表变量</p>

<pre>
<code class="language-bash">include(print_list.cmake)

set(a "a;b;c")
set(b a;b;c)
set(c a b c)

print_list(a) # 输出:a | b | c
print_list(b) # 输出:a | b | c
print_list(c) # 输出:a | b | c</code></pre>

<p> &nbsp;</p>

<p><br />
<strong>控制结构</strong></p>

<p>if while&nbsp; foreach&nbsp; break continue</p>

<p>&nbsp;</p>

<p><br />
<strong>条件语法&nbsp;</strong></p>

<p>常量条件</p>

<p>&nbsp;</p>

<p>变量条件</p>

<pre>
<code>cmake_minimum_required(VERSION 3.20)

set(on "OFF")

if(on)
    message("ON")
else()
    message("OFF")
endif()

if(${on})
    message("ON")
else()
    message("OFF")
endif()</code></pre>

<p> &nbsp;</p>

<p>字符串条件&nbsp;</p>

<pre>
<code>if(ABC)
else()
    message("ABC不是一个已定义的变量,因此条件为假")
endif()

set(a "XYZ")
set(b "0")
set(c "a-NOTFOUND")

if(a)
    message("a是一个变量,其值非假值常量,因此条件为真")
endif()

if(b)
else()
    message("b是一个变量,其值为假值常量,因此条件为假")
endif()

if(c)
else()
    message("c是一个变量,其值为假值常量,因此条件为假")
endif()</code></pre>

<p> &nbsp;</p>

<p>逻辑运算</p>

<pre>
<code>cmake_minimum_required(VERSION 3.20)

if(NOT OFF)
    message("NOT OFF为真")
endif()

if(ON AND YES)
    message("ON AND YES为真")
endif()

if(TRUE AND NOTFOUND)
else()
    message("TRUE AND NOTFOUND为假")
endif()

if(A-NOTFOUND OR YES)
    message("A-NOTFOUND OR YES为真")
endif()</code></pre>

<p></p>

<p>单参数条件</p>

<pre>
<code>set(a 1)

if(DEFINED a)
    message("DEFINED a为真")
endif()

if(CACHE{b})
else()
    message("CACHE{b}为假")
endif()

if(COMMAND set)
    message("COMMAND set为真")
endif()

if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/逻辑运算.cmake")
    message("EXISTS \"${CMAKE_CURRENT_LIST_DIR}/逻辑运算.cmake\"为真")
endif()</code></pre>

<p> &nbsp;</p>

<p>双参数条件</p>

<pre>
<code>cmake_minimum_required(VERSION 3.20)

set(a 10)
set(b "abc")
set(list 1;10;100)

if(11 GREATER a)
    message("11 GREATER a为真")
endif()

if(1 LESS 2)
    message("1 LESS 2为真")
endif()

if(b STRLESS "b")
    message("b LESS \"b\"为真")
endif()

if(1.2.3 VERSION_LESS 1.10.1)
    message("1.2.3 LESS 1.10.1为真")
endif()

if(abc MATCHES a..)
    message("abc MATCHES a..为真")
endif()

if(ab MATCHES a..)
else()
    message("ab MATCHES a..为假")
endif()

if(a IN_LIST list)
    message("a IN_LIST list为真")
endif()</code></pre>

<p>&nbsp; &nbsp;</p>

<p>括号和条件优先级</p>

<pre>
<code>cmake_minimum_required(VERSION 3.20)

if(NOT TRUE AND FALSE OR TRUE)
    message("NOT FALSE AND TRUE OR FALSE为真")
endif()

if(NOT (TRUE AND (FALSE OR TRUE)))
else()
    message("NOT FALSE AND TRUE OR FALSE为假")
endif()</code></pre>

<p> &nbsp;&nbsp;</p>

<p>变量展开</p>

<pre>
<code>cmake_minimum_required(VERSION 3.20)

set(A FALSE)
set(B "A")

if(B)
    message("B为真")
endif()

if(${B})
else()
    message("\${B}为假")
endif()

while(NOT ${B})
    message("NOT \${B}为真")
    break()
endwhile()</code></pre>

<p> &nbsp;<br />
<strong>命令定义</strong></p>

<p>宏定义</p>

<pre>
<code>macro(my_macro a b)
    set(result "参数a: ${a}, 参数b: ${b}")
endmacro()

my_macro(x y)
message("${result}") # 输出:参数a: x, 参数b: y

MY_macro(A;B)
message("${result}") # 输出:参数a: A, 参数b: B

MY_MACRO(你 好)
message("${result}") # 输出:参数a: 你, 参数b: 好</code></pre>

<p> &nbsp;</p>

<p>函数定义</p>

<pre>
<code>function(my_func a b)
    set(result "参数a: ${a}, 参数b: ${b}" PARENT_SCOPE)
endfunction()

my_func(x y)
message("${result}") # 输出:参数a: x, 参数b: y

MY_func(A;B)
message("${result}") # 输出:参数a: A, 参数b: B

MY_FUNC(你 好)
message("${result}") # 输出:参数a: 你, 参数b: 好</code></pre>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>参数访问&nbsp; &nbsp;</p>

<pre>
<code>macro(my_macro p)
    message("ARGC: ${ARGC}")
    message("ARGV: ${ARGV}")
    message("ARGN: ${ARGN}")
    message("ARGV0: ${ARGV0}, ARGV1: ${ARGV1}")
endmacro()

function(my_func p)
    message("ARGC: ${ARGC}")
    message("ARGV: ${ARGV}")
    message("ARGN: ${ARGN}")
    message("ARGV0: ${ARGV0}, ARGV1: ${ARGV1}")
endfunction()

my_macro(x y z)
my_func(x y z)</code></pre>

<p> &nbsp;</p>

<p>参数的设计与解析</p>

<pre>
<code>function(my_copy_func)
    message("ARGN: ${ARGN}")

    set(options OVERWRITE MOVE)
    set(oneValueArgs DESTINATION)
    set(multiValueArgs PATHS)

    cmake_parse_arguments(
      my
      "${options}" "${oneValueArgs}" "${multiValueArgs}"
      ${ARGN}
    )

    message("OVERWRITE:\t${my_OVERWRITE}")
    message("MOVE:\t\t${my_MOVE}")
    message("DESTINATION:\t${my_DESTINATION}")
    message("PATHS: \t\t${my_PATHS}")
    message("---")
endfunction()

my_copy_func(DESTINATION ".." PATHS "1.txt" "2.txt" OVERWRITE)
my_copy_func(MOVE DESTINATION "../.." PATHS "3.txt" "4.txt")
my_copy_func(DESTINATION "../folder;name" PATHS 1.txt;2.txt)</code></pre>

<p> &nbsp;</p>

<p>宏和函数参数的区别</p>

<pre>
<code>macro(my_macro p)
    message("-- my_macro --")

    if(p)
      message("p为真")
    endif()

    set(i 1)
    message("ARGV i: ${ARGV${i}}")
endmacro()

function(my_func p)
    message("-- my_func --")

    if(p)
      message("p为真")
    endif()

    set(i 1)
    message("ARGV i: ${ARGV${i}}")
endfunction(my_func)

my_macro(ON x)
my_func(ON x)</code></pre>

<p> &nbsp;</p>

chejm 发表于 2024-10-21 14:27

<p>感谢楼主分享的cmake基本语法知识,内容详实,通俗易懂,受益匪浅</p>
页: [1]
查看完整版本: 《Cmake构建实战》3 Cmake基础语法学习