CMake入门:使用CMake构建项目
编程 rtthread c语言 编译 RTOS 56

CMake通过CMakelist进行项目构建,它是一个跨平台的工具,只需要一份CMakelist就可以在全平台构建项目,CMake会控制对应构建系统(如Makefile或Ninja)完成构建,非常方便。

本文以Clion新建项目生成的cmakelist和开源项目RT-Thread所构建的cmakelist做为示例进行介绍。

单文件cmakelist

以下是一个cmakelist的示例:

cmake_minimum_required(VERSION 3.28)
project(4_2 C)
set(CMAKE_C_STANDARD 11)
add_executable(4_2 main.c)

第一行cmake_minimum_required:构建项目所需的最低cmake版本

第二行project:4_2是项目的名字,C是指定的语言,也可以不指定 like this:project(4_2) ,如果不指定,会默认支持C语言。(显式指定语言可以避免混淆)

第三行set:设置c的版本(这一行可以不写,则编译器会使用默认版本)

第四行add_executable:4_2是项目需要构建的可执行文件,由main.c编译而成

多文件cmakelist

如果你用到三个c文件,你可以这样写:

cmake_minimum_required(VERSION 3.28)
project(7_1 C)

set(CMAKE_C_STANDARD 11)

add_executable(7_1 main.c
        wheel.c
        wheel.h
        sorts.c
        sorts.h)

这样会把main.c和其他几个c文件一起编译进可执行文件中。

等等,这里出现了问题,我们知道h文件是编译时编译器会自动寻找的,也就是说,只需要这样就可以了:

add_executable(7_1 main.c
        wheel.c
        sorts.c
)

不管包不包含h文件,构建都会正常进行,包含h文件在语法上是支持的。

进阶 CMake语法

实际项目中所使用的.c文件远远不止于此,因此,掌握一些cmake基本语法对大工程的构建至关重要。

INCLUDE_DIRECTORIES()

项目中用到的头文件应该被INCLUDE_DIRECTORIES()这个函数所包含。包含的是.h文件存在的那个文件夹。文件夹与文件夹之间可以只用空格分开,也可以换行使阅读更清晰。

INCLUDE_DIRECTORIES(
	.
	applications
	board
	board/CubeMX_Config/Inc
	packages/CMSIS-Core-latest/Include
)

在上文我们刚说可以不用指定头文件位置,为什么在此又用对应的函数呢?

当你在源文件中使用#include "header.h"#include <header.h>时,编译器需要知道header.h文件的具体位置,如果头文件位于当前源文件目录之外,编译器需要额外的搜索路径来找到这些头文件。如果不添加路径,可能会有找不到h文件的报错。

此外,在大型项目中,头文件可能分布在多个目录中。通过include_directories()target_include_directories(),可以清晰地指定这些路径,使项目结构更加灵活和可维护。

ADD_DEFINITIONS()

ADD_DEFINITIONS()命令用于向编译器添加预定义的宏(-D选项),

ADD_DEFINITIONS(
	-DSTM32F103xB
	-DUSE_HAL_DRIVER
	-D__RTTHREAD__
	-DRT_USING_NEWLIBC
	-DRT_USING_LIBC
	-D_POSIX_C_SOURCE=1
)

如果使用gcc作为编译器,CMake会生成类似以下的命令行:

gcc -DSTMD32F103xB -DUSE_HAL_DRIVER -D__RTTHREAD__ -DRT_USING_NEWLIBC -DRT_USING_LIBC -D_POSIX_C_SOURCE=1 -c main.c -o main.o

SET()

SET()可以把一组C源文件的路径存储到变量中

RT_FINSH_SOURCES 存储的就是后面几行c文件

SET(RT_FINSH_SOURCES
	../../../components/finsh/cmd.c
	../../../components/finsh/shell.c
	../../../components/finsh/msh_parse.c
	../../../components/finsh/msh.c
)

本质是把变量名设置一个值,如:

SET(MY_VARIABLE "Hello, World!")
SET(ENABLE_DEBUG TRUE)

ADD_LIBRARY()

ADD_LIBRARY() 是 CMake 中的一个核心命令,用于创建一个库目标(library target)

ADD_LIBRARY(rtt_Finsh OBJECT ${RT_FINSH_SOURCES})

rtt_Finsh:是对象库的名称

OBJECT:这个关键字指定了要创建的对象库。它告诉 CMake 不要生成一个独立的库文件,而是将源文件编译成对象文件

${RT_FINSH_SOURCES}RT_FINSH_SOURCES所存储的c文件会被编译成对象文件,并存储在对象库 rtt_Finsh

此外,if语句也是支持的

if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/custom.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/custom.cmake)
endif()

此外,CMake命令的名称在语法上是大小写不敏感的,但变量名称是大小写敏感的。

因此你可以看到这样的写法:CMAKE_MINIMUM_REQUIRED(VERSION 3.10)

也可以看到这样的写法:cmake_minimum_required(VERSION 3.10)

这二者是一样的

What else

cmake还可以跟kconfig连用,实现更自动化的项目构建,比如RT-Thread就使用menuconfig进行项目配置,生成.config文件,使用Scons命令根据.config、sconscript文件控制cmakelist的生成,将menuconfig配置后不需要编译的文件剔除出去,完成裁剪。最后用cmakelist完成项目构建。

CMake入门:使用CMake构建项目
https://maoyx.com/archives/shi-yong-cmakegou-jian-xiang-mu
作者
千久源
发布于
更新于
许可