CMake入门:CMake简介、CMakeLists.txt基本语法、project()与add_executable()
各位同学好,我是老张。今天咱们正式开始CMake的学习之旅。说实话,我最早接触CMake的时候也觉得很头大——明明Makefile写得挺顺手的,干嘛要学这个?后来在嵌入式项目里被各种平台、编译器折腾得够呛,才明白CMake这东西,真香。
CMake是什么?为什么需要它?
CMake,全称Cross-platform Make。说白了,它是一个构建系统生成器。你写一份CMakeLists.txt,它就能帮你生成对应平台的Makefile、Visual Studio工程、Xcode工程等等。
我举个例子你就明白了。我在做STM32项目时,代码要在Windows上编译,同事用Linux,还有人用Mac。如果每个人手写Makefile,那维护成本简直灾难。CMake一出马,一份配置文件,三平台通吃。
核心思想:CMake不直接编译代码,它负责生成"编译代码的脚本"。你只管描述"我要编译什么、用什么工具链",剩下的交给CMake。
CMakeLists.txt——CMake的灵魂
每个CMake项目,根目录下必须有一个CMakeLists.txt文件。这是CMake的入口,也是你与CMake对话的唯一方式。
它的语法其实很简单,我总结为三句话:
- 命令不区分大小写,但习惯用小写
- 参数用空格分隔,字符串用双引号包起来
- 注释用#号,跟Shell脚本一样
来看一个最基础的例子:
# 这是注释
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
add_executable(hello main.c)
就这三行,一个完整的CMake项目就搭起来了。是不是比Makefile清爽多了?
project()——给项目起个名
project()是每个CMakeLists.txt里必须有的命令。它的作用不只是起名字,还会帮你设置一堆有用的变量。
语法很简单:
project(<项目名> [语言列表])
比如:
project(MyApp C CXX ASM)
这表示项目名叫MyApp,用C、C++和汇编语言。如果不指定语言,默认只启用C和C++。
我的习惯:在嵌入式项目中,我通常会显式写上project(MyProject C ASM)。因为很多MCU的启动代码是汇编写的,你不写ASM,CMake可能找不到汇编器,编译直接报错。我曾经在这个坑里爬了半小时...
project()执行后,CMake会自动生成几个变量:
| 变量名 | 含义 | 示例值 |
|---|---|---|
| PROJECT_NAME | 项目名称 | MyApp |
| PROJECT_SOURCE_DIR | 项目源码根目录 | /home/user/myapp |
| PROJECT_BINARY_DIR | 构建目录 | /home/user/myapp/build |
| CMAKE_PROJECT_NAME | 顶层项目名 | MyApp |
嗯,这里要注意:PROJECT_SOURCE_DIR和CMAKE_SOURCE_DIR在单项目时是一样的,但如果你用了add_subdirectory()引入子项目,它们就有区别了。这个后面再细说。
add_executable()——生成可执行文件
这个命令就是告诉CMake:我要生成一个可执行文件,源文件有哪些。
语法:
add_executable(<目标名> [源文件列表])
比如:
add_executable(hello main.c utils.c uart.c)
这就会生成一个叫hello的可执行文件(Windows下是hello.exe),由main.c、utils.c、uart.c编译链接而成。
避坑指南:我曾经犯过一个低级错误——把头文件也写进了add_executable里。比如add_executable(hello main.c utils.h)。CMake不会报错,但头文件会被当成源文件处理,编译时会出奇怪的问题。记住:add_executable只放.c/.cpp/.s文件,头文件用target_include_directories管理。
一个完整的入门示例
咱们来写一个完整的例子,把上面两个命令串起来:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# 项目名:Blinky,语言:C和汇编
project(Blinky C ASM)
# 生成可执行文件blinky.elf
add_executable(blinky.elf
main.c
startup_stm32f4.s
system_stm32f4.c
)
然后在终端里执行:
mkdir build
cd build
cmake ..
make
搞定!blinky.elf就生成在build目录下了。
知识体系总览
下面这张图,帮你把今天讲的内容串起来:
几个实用小技巧
最后分享几个我平时常用的写法:
- 源文件少的时候直接写:
add_executable(app main.c),简单粗暴 - 源文件多的时候用变量:
set(SRC_LIST
main.c
driver/gpio.c
driver/uart.c
driver/spi.c
)
add_executable(app ${SRC_LIST})
这样写,后期加文件只需要改set那一块,不用动add_executable那行。我在维护一个200+源文件的工程时,这个习惯帮我省了不少事。
关于cmake_minimum_required:我建议你写cmake_minimum_required(VERSION 3.10)或更高。太老的版本不支持很多现代特性,比如后面要讲的target_compile_features。但也不要写太高,比如3.30,因为有些客户的服务器还在用Ubuntu 18.04,自带的CMake才3.10。
好了,今天的内容就到这里。CMake入门其实不难,记住project()和add_executable()这两个命令,你就能跑起来第一个CMake项目了。下一节咱们会深入聊聊变量、条件判断和循环,这些都是写复杂构建脚本的基础。