CMake的常见用法总结

初识CMake

C/C++项目规模大了,Makefile脚本很可能也随之膨胀变得难以维护,比如著名的KDE项目就因为此原因切换到了CMake。编写Makefile涉及了要自己用GCC命令来推导C/C++的头文件依赖,自己用Makefile的内置函数来组织构建文件,自己组织编译的输出信息,维护编译输出的中间文件的目录等等。而CMake很好的解决了这些问题,CMake有更多简单易用的命令,更简洁的语法来组织编译工程,然后自动生成Makefile,这些自动生成Makefile就包含了自动推导头文件依赖,更加美观清晰的输出信息,各种.o, .i, .s target一应俱全,非常方便,而且跨平台。对了,JetBrains CLion IDE就是用CMake组织构建系统的。看为一下官方对CMake的介绍:

CMake is an extensible, open-source system that manages the build process in an operating system and in a compiler-independent manner. Unlike many cross-platform systems, CMake is designed to be used in conjunction with the native build environment.
Simple configuration files placed in each source directory (called CMakeLists.txt files) are used to generate standard build files .

官方的入门教程: https://cmake.org/cmake-tutorial/
官方的帮助索引: https://cmake.org/cmake/help/latest/index.html

快速入门CMake,可以从搭建一个小项目的CMake编译系统做起,然后再看一些知名项目的CMake编写,如Google Test等。有一定理解后,边查官方文档,边改进自己的小项目,逐渐的深入掌握。编写CMake脚本,推荐使用vs code,安装cmake插件,可以智能提示,十分的方便。

CMake常见用法

首先说一点,CMakeLists.txt 文件中不区分大小写。查看命令的index如下:
https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html
通过名字就可以猜出大致的功能。有一定基础后,编写或修改CMake脚本,直接插帮助index定位要用的命令即可。看多了就会了解CMake的一些命令起名的风格以及约定用法,举一反三。

变量的用法与调试

定义变量:set 命令,定义normal var、环境变量、cache entry等;
取消定义:unset 命令,取消变量的定义;
使用变量:${var}引用变量,$ENV{var}引用环境变量,在 IF 等语句中直接使用变量名而不通过${}取值;
调试方法:message 命令,可以打印输出;

常见的内置变量: https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html

更多的内置命令可以看前面官方给出的文档链接。

设置头文件搜索路径

include_directories 命令,添加头文件搜索路径,最终就是在生成的Makefile中把头文件搜索目录作为命令行参数传给了编译器。

添加目录下所有源文件

aux_source_directory 命令,找到目录下所有的源文件存到一个变量中。

设置编译目标

add_executable 编译可执行文件目标;
add_library 编译静态或动态库目标,通过STATIC | SHARED来控制;
add_custom_target 目标不是一个真实文件,总会执行到,类似Makefile里的all目标;

设置链接文件和搜索路径

link_directories 链接器的搜索目录;
link_libraries 后续的所有target都会链接;
target_link_libraries 给指定target链接对应的库文件;

设置编译宏和编译选项

注意一下add_compile_options和CMAKE_CXX_FLAGS的区别:

  • add_compile_options命令添加的编译选项是针对所有编译器的(包括c和c++编译器);
  • set命令设置CMAKE_C_FLAGS或CMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的;

控制语句if/while等的使用

if, 条件执行一些命令;
while 循环执行一些命令;
foreach 对一组list都执行一些命令块;
function 顶一个逻辑块方便后续调用;
return 从文件目录或函数返回;

添加子目录

add_subdirectory 添加要编译的子目录,会加载子目录下CMakeLists.txt。此命令组织大型工程必备。

添加别的CMake脚本

include 为了是CMake脚本更简洁清晰,可以把一些脚本写到别的CMake文件中,include进来用就好。

CMake的命令行接口

cmake命令行接口,cmake命令常常这么用,在工程根目录下新建一个build目录,进入执行cmake ..来进行编译。

CMake demo用法举例

一个项目的目录结构如下:

test
├── build
├── CMakeLists.txt
└── src
    ├── add
    │   ├── add.cpp
    │   ├── add.h
    │   └── CMakeLists.txt
    ├── include
    │   └── sub.h
    ├── main.cpp
    └── sub.cpp

其中项目test根目录CMake文件如下:

cmake_minimum_required(VERSION 3.10)

project(HELLOWORLD)

# 设置变量:目标可执行文件名
set(TARGET helloworld)

# 设置编译选项
add_compile_options(
    -m64 -Wall -Werror 
    -O0 -ggdb3
)

# 添加头文件搜索路径
include_directories(
    ./src/include
    ./src/add
)

# 添加一个目录下的所有源文件
aux_source_directory(./src DIR_SRCS)
message("src files @dir{}" ${DIR_SRCS})

# 添加子目录 --> 子目录用来编译共享库 libadd.so
add_subdirectory(src/add)

# 编译可执行文件
add_executable(${TARGET} ${DIR_SRCS})
target_link_libraries(${TARGET} add)

子目录add下的CMake文件:

message("build libadd.so")
add_library(add SHARED add.cpp)

代码文件内容十分简单,main.cpp调用了add, sub两个函数,这两个函数分别在add.cpp和sub.cpp实现了。这里通过编译工程把add编译为了共享库so的形式,编译参数则开启了所有告警等。

执行的时候,进入到build目录,cmake .. 然后 make 就OK了。

总结

CMake描述一个C/++项目的构建系统是比Makefile要来的清晰的。很多常用的功能都被CMake的命令很好的封装了,调用起来也很方便,并且CMake生成的Makefile用起来也很顺手,输出清晰美观,编译各个单目标都一应俱全。常用的命令的也不算太多,使用的时候多查官方的帮助文档,直接看目录索引按照字面意思找就可以。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值