Skip to content

CMake语法

CMake项目是基于 CMakeLists.txt 构建的,在 CMakeLists.txt 中(或 *.cmake 中)我们用到的就是CMake Language。

CMake Language的语法非常像一些命令式编程语言。

执行从源树(CMakeLists.txt)的跟文件开始。

CMake命令行工具是由五个可执行文件构成

  • cmake
  • ctest
  • cpack
  • cmake-gui
  • ccmake

如何不通过CMakeLists.txt,运行CMake

shell
cmake -P *.cmake

这种用法很少在项目中用到,但适合学习CMake的语法

如何打印

使用message

cmake
message("can you see 
something?")

message(------------------------)

message([[can you see 
something?]])

message(------------------------)

message(can you see 
something?)

message(------------------------)

# 获取CMake中的信息 打印CMake版本信息
message(${CMAKE_VERSION})
$ ls
message.cmake
$ cmake -P message.cmake 
can you see 
something?
------------------------
can you see 
something?
------------------------
canyouseesomething?
------------------------
3.25.1

变量操作set、list

CMake中的变量分为两种

  • CMake提供的变量
  • 自定义的变量

注意

  • CMake变量的
  • CMake中的变量在
  • CMake获取变量${变量名}
  • 变量的基础操作是set()unset(),但你也可以用liststring操作变

set方法

cmake
set(<variable> <value> ... [PARENT_SCOPE])
  • set可以给一个变量设置多个值
  • 变量内部存储时使用;分割,但显示时只进行连接处理

进行实际使用测试

cmake
cmake_minimum_required(VERSION 3.20.0)

set(var1 test 1)
set(var2 "test 2")
set("test spaces" "The variable name has Spaces in it.")

message(${var1})
message(${var2})
message((${test\ spaces}))

message(-------------------------------------)

# 设置多个值
set(multipleVar value1 value2)
message(${multipleVar})

message(-------------------------------------)

# 给一个变量重复设置值
set(multipleVar value3 value4)
message(${multipleVar})

set(multipleVar value5;value6)
message(${multipleVar})

message(-------------------------------------)

# 获取环境变量
message($ENV{PATH})

message(-------------------------------------)

# 往环境变量中添加变量
set(ENV{CXX} g++)
message($ENV{CXX})

message(-------------------------------------)

# unset
unset(ENV{CXX})
message($ENV{CXX})
$ cmake -P set.cmake 
test1
test 2
(The variable name has Spaces in it.)
-------------------------------------
value1value2
-------------------------------------
value3value4
value5value6
-------------------------------------
/home/zm/.vscode-server/bin/8b3775030ed1a69b13e4f4c628c612102e30a681/bin/remote-cli:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/mysql/bin:/usr/local/mysql/bin
-------------------------------------
g++
-------------------------------------
CMake Error at set.cmake:41 (message):
message called with incorrect number of arguments

list方法

cmake
list(APPEND <list> [<element> ...]) # 向列表中添加元素
list(REMOVE_ITEM <list> <value> [value...]) # 从列表中删除元素
list(LENGTH <list> <output variable>) # 获取列表元素个数
list(FIND <list> <value> <out-variable>) # 在列表中查找元素返回索引
list(INSERT <list> <index> [<element> ...]) # 在index位置插入元素
list(REVERSE <list>) # 反转list
list(SORT <list> [...]) # 排序list

流程控制

条件流程控制if

cmake
if(<condition>)
    <commands>
elseif(<condition>)
    <commands>
else()
    <commands>
endif()

循环流程控制foreach、while

  • break
  • continue
cmake
foreach(<loop_variable> RANGE <max>)
    <commands>
endforeach()

foreach(<loop_variable> RANGE <min> <max> [<step>])
foreach(<loop_variable> IN [LISTS <lists>] [ITEMS <items>])

while(<condition>)
    <commands>
endwhile()

函数

定义函数的语法

cmake
function(<name> [<argument> ...])
    <commands>
endfunction()

实例测试

cmake
cmake_minimum_required(VERSION 3.20.0)

function(test arg1)
    message("function name:" ${CMAKE_CURRENT_FUNCTION})
    message("function argv[0]:" ${arg1})
    message("function argv[0]:" ${ARGV0})
    message("function argv[1]:" ${ARGV1})
    message("function argv[2]:" ${ARGV2})
    set(arg1 "Testing changes")
    message("function argv[0]:" ${arg1})
    message("function argv[0]:" ${ARGV0})
endfunction(test arg1)

set(a "value1")
message(${a})
test(${a} "value2")
message(${a})
$ cmake -P function.cmake 
value1
function name:test
function argv[0]:value1
function argv[0]:value1
function argv[1]:value2
function argv[2]:
function argv[0]:Testing changes
function argv[0]:value1
value1

通过测试我们可以看出,传入的参数在函数内被修改掉了,但是在函数外边的变量不受影响

作用域

CMake有两种作用域

  • function scope 函数作用域
  • directory scope 当从add_subdirectory()命令执行嵌套目录中的CMakeLists.txt列表文件时,注意父CMakeLists.txt中的变量可以被子CMakeLists.txt使用

构建项目测试

shell
$ tree
.
├── CMakeLists.txt
└── test
    └── CMakeLists.txt

2 directories, 2 files
$ cat CMakeLists.txt 
cmake_minimum_required(VERSION 3.20.0)

project(scope)

set(hello "hello world")

add_subdirectory(test)
$ cat test/CMakeLists.txt 
message("subdirectory:" ${hello})
$ cmake -B build
-- The C compiler identification is GNU 12.3.0
-- The CXX compiler identification is GNU 12.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
subdirectory:hello world
-- Configuring done
-- Generating done
-- Build files have been written to: /media/psf/code/cmake/scope/build

宏定义在CMake中尽量不要使用,使用宏定义无疑会增加CMake的阅读难度

cmake
macro(<macro_name> [<arg> ...])
    <commands>
endmacro()

实例测试

cmake
cmake_minimum_required(VERSION 3.20.0)

macro(test arg1)
    message("arg1:" ${arg1})
    set(arg1 "Testing changes")
    set(a "Testing changes")
    message("arg1:" ${arg1})
endmacro(test arg1)

set(a "This is a")
message("a:" ${a})
test(${a})
message("a:" ${a})
$ cmake -P macro.cmake 
a:This is a
arg1:This is a
arg1:This is a
a:Testing changes