CMake快速上手

由于项目需要使用CMake,对CMake一窍不通的我开始一边查资料一边写CMake。不得不说,CMake的中文资料真的不多,CMake有大量的变量和函数,很容易看的一头雾水。
在看了很多的资料后,建议有时间直接看官方的文档进行学习。
这里记录一些我写的CMake脚本和注解,提供给入门新手学习。

脚本说明&项目信息

CMake文件开头都会设置支持的CMake最小版本号、项目名称和项目使用的语言。不同的cmake版本,使用起来也会略有差异。

1
2
3
4
# 设置cmake最小版本号
cmake_minimum_required(VERSION 3.13)
# 设置项目名称和项目使用的语言
project(sysumoc-test LANGUAGES CXX)

设置变量

CMake设置变量使用关键字set设置,比如我们可以设置项目使用的c++标准。项目使用的是c++11,所以我们设置CMAKE_CXX_STANDARD变量为11。

1
2
3
4
# set the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

CMake有大量的变量,这些变量与编译密切相关。但是直接从文档中学习这些变量并不是聪明的事,建议阅读其他人写的CMake文件,掌握一些常见的变量,下面是我整理的常见的变量。

常见变量

  • CMAKE_CXX_STANDARD 显式声明程序使用c++11进行编译,也可以设置compiler flag来指定c++版本;
  • CMAKE_CXX_STANDARD_REQUIRED 设置指定的C++编译器版本是必须的,如果不设置,或者为OFF,则指定版本不可用时,会使用上一版本。如果设置为ON,不满足条件时会停止构建项目;
  • CMAKE_CXX_EXTENSIONS 如果值为ON,则会使用更加通用的参数,比如使用std=c++14 而不是-std=gnu++14;
  • CMAKE_ARCHIVE_OUTPUT_DIRECTORY 静态库的存放目录;
  • CMAKE_LIBRARY_OUTPUT_DIRECTORY 动态库的存放目录;
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY 可执行文件的存放目录;
  • CMAKE_BINARY_DIR 一般情况下可以认为就是工程的顶层目录;
  • CMAKE_SOURCE_DIR 一般情况下可以认为就是工程的顶层目录;
  • CMAKE_CURRENT_SOURCE_DIR CMakeLists.txt文件所在的路径;

打印信息

打印信息是一个调试CMake脚本的好方法,尤其是我们对一些路径或文件的变量不确定时。可以使用以下语句来打印变量和信息

1
message([<mode>] "message text" ...)

信息的类型有:STATUSDEPRECATIONAUTHOR_WARNINGWARNING等可选,具体可以查阅文档

使用三方库

第三方库有很多种,一种是被广泛使用的官方库,例如MPI。对于这种库,我们可以使用find_package命令来进行查找,例如下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.11)

# 项目信息
project(Demo1)

# 输出MPI路径
message(STATUS "MPI_INCLUDE_PATH = ${MPI_INCLUDE_PATH}")

# 查找MPI库路径
find_package(MPI REQUIRED)

# 输出MPI路径
message(STATUS "MPI_FOUND = ${MPI_FOUND}")
message(STATUS "MPI_INCLUDE_PATH = ${MPI_INCLUDE_PATH}")
message(STATUS "MPI_LIBRARIES = ${MPI_LIBRARIES}")

输出结果为:

1
2
3
4
5
6
7
-- MPI_INCLUDE_PATH =
-- MPI_FOUND = TRUE
-- MPI_INCLUDE_PATH = /usr/include/mpich
-- MPI_LIBRARIES = /usr/lib/x86_64-linux-gnu/libmpichcxx.so;/usr/lib/x86_64-linux-gnu/libmpich.so
-- Configuring done
-- Generating done
-- Build files have been written to: ...

find_package命令可以从系统中查找指定第三方库,指定REQUIRED后,如果没有找到库则会报错。查找的结果会保存在变量中。

  • <package>_FOUND保存是否找到库
  • <package>_INCLUDE_PATH头文件所在的路径
  • <package>_LIBRARIES库文件所在的路径

找到库后便可以进行链接操作

1
2
3
4
5
6
7
8
# 设置头文件路径,相当与gcc中的-I
include_directories(${MPI_INCLUDE_PATH})

# 设置库文件路径,相当与gcc中的-L
link_directories(${MPI_LIBRARIES})

# 设置链接的库,相当于gcc中的-l
target_link_libraries(${MPI_LIBRARIES})

注意:链接库需要在生成可执行文件后。

设置编译选项

在cmake脚本中,设置编译选项(配置编译器)有如下三种方法:

1、add_compile_options命令

1
add_compile_options(-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes)

2、add_definitions命令

1
ADD_DEFINITIONS("-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes)

3、set命令修改CMAKE_CXX_FLAGSCMAKE_C_FLAGS

1
set(CMAKE_C_FLAGS "-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes)

使用这三种方式在有的情况下效果是一样的,但请注意它们还是有区别的:
add_compile_options命令和add_definitions添加的编译选项是针对所有编译器的(包括c和c++编译器),而set命令设置CMAKE_C_FLAGSCMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的。

生成可执行文件

使用add_executable命令可以生成可执行文件。

1
add_executable(main src/main.cpp)

CMake编译MPI程序

main.cpp文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "bits/stdc++.h"
#include "mpi.h"

int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
int rank;
int size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
printf("hello world from rank %d of %d\n", rank, size);
MPI_Finalize();
return 0;
}

CMakeLists.txt文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.17)

# 项目名和信息
project (mpi_hello LANGUAGES CXX)

# 查找MPI库路径
find_package(MPI REQUIRED)

# 设置编译参数
add_compile_options(-Wall -O3)

# 设置头文件路径,相当与gcc中的-I
include_directories(SYSTEM ${MPI_INCLUDE_PATH})

# 生成可执行文件
add_executable(main main.cpp)

# 设置链接的库,相当于gcc中的-l
target_link_libraries(main ${MPI_LIBRARIES})

输入cmake .命令生成makefile文件,make命令编程程序。

1
2
3
4
5
6
mpiexec -n 4 ./main # 运行程序
# 运行结果如下
hello world from rank 0 of 4
hello world from rank 3 of 4
hello world from rank 1 of 4
hello world from rank 2 of 4

参考资料

CMake官方文档
博客:cmake 常用变量和常用环境变量查表手册

作者

echo

发布于

2023-01-18

更新于

2024-08-10

许可协议

评论