引言
CMake 是一个跨平台的构建系统生成器,用于自动化构建、测试和打包软件项目的过程。CMake 通过一系列源代码文件和配置设置,生成平台特定的构建文件(例如 Makefile、Visual Studio 项目文件等)。
CMake语法
- 依次使用以下命令生成项目(对于CmakeLists.txt)
|
|
-
语法简介
cmake -P *.cmake命令来运行cmake文件1 2 3 4 5 6 7 8 9 10 11 12# 单行打印 message("hello") message(hello) # 多行打印 message("first line second line") message([[first line second line]]) # 打印cmake版本号,使用CMAKE_VERSION变量 ${} message(${CMAKE_VERSION}) -
set设置变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26set(Var1 "hello") set(Var2 world) # 打印单行hello world message(${Var1} ${Var2}) # 打印多行hello world message("${Var1} ${Var2}") message("------------------------") set(VarLists a1 a2) message(${VarLists}) #a1a2 # 打印环境变量 message($ENV{PATH}) # 创建cmake项目的环境变量 set(ENV{CXX} "g++") message($ENV{CXX}) # 删除刚刚创建的环境变量 unset(ENV{CXX}) -
list
- list(操作方式 操作对象 可能有操作返回结果的变量)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20list(APPEND port p1 p2 p3) message(${port}) # p1p2p3 list(LENGTH port len) message(${len}) # 3 (变量长度为3) list(FIND port p2 index) message(${index}) # 1 (p2在1的位置) list(REMOVE_ITEM port p1) message(${port}) # p2p3 (删除p1) list(INSERT port 1 p2.5) message(${port}) # p2p2.5p3 (在1位置插入p2.5) list(REVERSE port) message(${port}) # p3p2.5p2 (进行反转) list(SORT port) message(${port}) # p2p2.5p3 (进行排序) -
流程控制
- if流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34set(VAR1 TRUE) set(VAR2 FALSE) if(VAR1) # 简单判断 message(TRUE) else() message(FALSE) endif() if(NOT VAR1) # NOT不能是not,大小写敏感 message(TRUE) else() message(FALSE) endif() if(VAR1 AND VAR2) # OR用法也是如此 message(TRUE) else() message(FALSE) endif() if(1 LESS 2) # 比较,其实还是字符串的比较 message("1 less 2") else() message("error") endif() if(2 GREATER 1) message("2 greater 1") endif() if(2 EQUAL "2") message("2 equal \"2\"") endif()- for流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20foreach(VAR RANGE 3) message(${VAR}) # 0 1 2 3 (跟一般编程语言区别很大) endforeach() set(MY_LISTS 1 2 3) foreach(VAR IN LISTS MY_LISTS ITEMS 4 f) message(${VAR}) # 1 2 3 4 f endforeach() message("----------------------") set(L1 one two three) set(L2 1 2 3 4) foreach(num IN ZIP_LISTS L1 L2) message("word = ${num_0}, num = ${num_1}") endforeach() # word = one, num = 1 # word = two, num = 2 # word = three, num = 3 # word = , num = 4
-
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21function(MyFunc FirstArg) # 函数名MyFunc message("MyFunc Name: ${CMAKE_CURRENT_FUNCTION}") message("FIRST ${FirstArg}") # 使用形参列表使用参数 set(FirstArg "New value") message("FirstArg again: ${FirstArg}") message("ARGV0 ${ARGV0}") # 不使用形参列表使用参数 message("ARGV1 ${ARGV1}") message("ARGV2 ${ARGV2}") endfunction() set(FirstArg "first value") MyFunc(${FirstArg} "value") # 可以传入和新参列表不一样数目的实参 message("FirstArg ${FirstArg}") # 函数内部修改不会改变函数外面 # MyFunc Name: MyFunc # FIRST first value # FirstArg again: New value # ARGV0 first value # ARGV1 value # ARGV2 # FirstArg first value -
宏
1 2 3 4 5 6 7 8 9 10 11 12 13macro(Test myVar) set(myVar "new value") # 新建的变量,不是上面的参数 message("argument: ${myVar}") #${myVar}会变为传入的myVar endmacro() set(myVar "First value") message("myVar: ${myVar}") Test("value") # 将宏代码复制到了这里 message("myVar: ${myVar}") # myVar: First value # argument: value # myVar: new value
简单的CMake项目
- 在这个简单的CMake项目中,有如下的项目结构
- 整个项目只有一个CMakeLists.txt,所有的源文件和头文件都放在项目目录中,bin中存放的是最终的可执行程序。

- CMakeLists.txt中的代码如下
|
|
分文件编写的的CMake项目
- 在这个份文件的CMake项目中,有如下的项目结构
- 整个项目只有一个CMakeLists.txt,src文件夹里面存放的是源文件,include文件夹中存放的是头文件,bin中存放的是最终的可执行程序。

- CMakeLists.txt中的代码如下
|
|
共享库
- 在创建共享库的项目中,有如下目录结构
- 注意到bin中多出了libcommon.dll动态链接库文件。同时,main程序在项目目录下,其他.cpp文件存放在了src目录中,头文件存放在了include目录中。

- CMakeLists.txt中的代码如下
|
|
CmakeLists嵌套
- 项目有如下目录结构
- 项目文件夹下有一个CmakeLists文件;src文件夹里有一个CmakeLists文件,主程序和几个类的文件夹;同时src中每个类各自的文件夹都包含了CmakeLists,.cpp,.h三个文件

-
嵌套使用的时候上层CmakeLists文件的变量会传入到下层的CmakeLists文件当中。
-
项目文件夹下的CmakeLists.txt代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16cmake_minimum_required(VERSION 3.29.0) project(planning VERSION 0.0.1 DESCRIPTION "a demo of cmake planning" LANGUAGES CXX ) set(CMAKE_CXX_STANDARD 17) # 一些后面要使用的变量 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) set(PROCESS_DIR ${CMAKE_SOURCE_DIR}/src/process) set(PNC_MAP_DIR ${CMAKE_SOURCE_DIR}/src/pnc_map) # 增加子目录 add_subdirectory(src) -
src文件夹下的CmakeLists.txt代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20project(planning_main) # 添加子目录 add_subdirectory(pnc_map) add_subdirectory(process) # 根据planning_main.cpp形成可执行文件 add_executable(${PROJECT_NAME} planning_main.cpp) # 生成可执行文件需要process.h target_include_directories(${PROJECT_NAME} PUBLIC ${PROCESS_DIR} ) # 链接库需要process库 target_link_libraries(${PROJECT_NAME} PUBLIC process ) -
两个类中的CmakeLists代码分别如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18project(process) add_library( ${PROJECT_NAME} SHARED process.cpp ) # 生成库需要pnc_map.h 注意,这是根据代码的关系决定,本例代码中,类process有pnc_maplei'x的成员变量 target_include_directories(${PROJECT_NAME} PUBLIC ${PNC_MAP_DIR} ) # 生成库需要pnc_map库 target_link_libraries(${PROJECT_NAME} PUBLIC pnc_map )1 2 3 4 5 6project(pnc_map) add_library( ${PROJECT_NAME} SHARED pnc_map.cpp )