Windows平台
1. 下载CMake和MinGW,并安装。
(1)CMake下载和安装:
下载地址:Download | CMake 可以直接下载如下安装程序进行安装:
安装时注意,选择将cmake命令加入系统环境变量,如下:
或者装完后手动配置环境变量,将CMake安装路径下的bin目录加入环境变量,如下:
打开终端或cmd测试CMake安装是否成功,如下表示成功:
(2)MinGW下载和安装:
下载地址:MinGW-w64 - for 32 and 64 bit Windows - Browse /mingw-w64 at SourceForge.net
可以直接下载如下安装程序进行安装:
安装时根据自己电脑选择,如我是64位系统:
装完手动配置环境变量,将MinGW安装路径下的bin目录加入环境变量(本人已装完,不知道安装过程中是否有和CMake一样的添加入环境变量的选项,有则无需手动配置):
打开终端或cmd测试MinGW安装是否成功,如下表示成功:
2. CMake的快速上手
本部分先熟悉一下CMake使用的大致流程,第三部分会展开介绍CMake的详细使用。
使用CMake构建简单的Hello world程序:
(1)创建项目文件夹demo,其中包含build和src两个子文件夹:
build文件夹用于存放CMake生成的文件,如CMake会生成GNU编译器的Makefile等文件,或Visual Studio编译器的项目文件,可执行文件等。
src文件夹用于存放源代码和CMakeLists.txt文件。
CMakeLists.txt文件用于存储cmake生成的构建文件的位置、编译器类型、编译选项等。
(2)在src文件夹下创建hello.cpp,写入Hello world程序。
(3)在src文件夹下创建CMakeLists.txt文件,写入如下内容:
cmake_minimum_required(VERSION 3.10) # 要求cmake最低版本为3.10
project(hello) # 项目名为hello
add_executable(hello hello.cpp) # 使用hello.cpp生成可执行文件hello.exe
(4)在项目文件夹下打开终端窗口,构建项目:
命令:cmake CMakeLists.txt的路径 ,如:
cmake ..\src
本人电脑默认使用Visual Studio的MSCV编译器进行构建,如下:
输入CMake --help命令查看所有编译器,找到Generators,前面带星号的是当前使用的编译器:
若需使用gcc或g++,则需在构建命令中加上 "MinGW Makefiles" ,如下:
cmake CMakeLists.txt -G "MinGW Makefiles" ..\src\
成功生成:
之后使用build选项进行编译链接:
此时build目录下生成了可以运行的hello.exe
3. CMake的详细使用
3.1 概念
a)目标文件(target):可执行文件(add_executable)、库文件(add_library);
b)命令(cmake-command):也称为函数;
c)变量(cmake-variable):以CMAKE_开头的变量名;
d)属性(cmake-properties):文件/文件夹都有各自的属性。
补充:
a)cmake命令不区分大小写,但参数、变量区分;
b)参数间使用空格或分号隔开;
c)使用${VAR}引用变量;
d)引号可加可不加,但若字符串中有空格必须加;
3.2 命令
(1)cmake_mininum_required
设置cmake的最低版本。
用法:
cmake_minimum_required(VERSION 版本号)
示例:
cmake_minimum_required(VERSION 3.10)
(2)project
设置项目名、版本号、语言。
用法:
# 用法1:
project(<项目名> [<语言>])
# 若未指定语言,则默认使用C和CXX(即C++)
# 用法2:
project(<项目名> [<VERSION 版本号>] [<LANGUAGES 语言>])
示例:
# 用法1:
project(demo C CXX)
# 项目名:demo,使用语言:C和C++
# 用法2:
project(demo VERSION 1.0 LANGUAGES C CXX)
# 项目名:demo,版本号:1.0,使用语言:C和C++
(3)message
输出信息。
用法:
message([<mode> "..."]
# mode有如下选项:
# STATUS:前缀加上 --
# SEND_ERROR:产生错误,跳过生成过程
# FATAL_ERROR:产生错误,终止运行
项目名会存储在变量PROJECT_NAME和CMAKE_PROJECT_NAME中(CMAKE_开头的变量为cmake内置变量);
源文件路径存储在变量PROJECT_SOURCE_DIR中,等价于<PROJECT_NAME>_SOURCE_DIR;
构建文件(即build文件夹)路径存储在变量PROJECT_BINARY_DIR中,等价于<PROJECT_NAME>_BINARY_DIR;
项目版本号存储在变量PROJECT_VERSION中,等价于<PROJECT_NAME>_VERSION;
项目主版本号存储在变量PROJECT_VERSION_MAJOR中,等价于<PROJECT_NAME>_VERSION_MAJOR;
项目次版本号存储在变量PROJECT_VERSION_MINOR中,等价于<PROJECT_NAME>_VERSION_MINOR;
示例:使用message命令打印上述部分变量,注意变量需使用${}引用:
build文件夹下打开终端,使用如下cmake命令构建:
(4)add_executable
用指定的源文件生成可执行文件。
用法:
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2...])
# name为生产的可执行文件名(与项目名无关)
# 如Windows系统会生成name.exe
示例:
add_executable(demo helloworld.cpp)
# 用helloworld.cpp生成demo.exe可执行文件(Windows)
(5)set
将变量设置为指定值。
用法:
set(<variable> <value>)
简单使用示例:
set(A 1)
# 将A设置为1
set(CMAKE_CXX_STANDARD 11)
# 设置C++标准,注:CMAKE_开头的变量为cmake内置变量
设置输出文件位置示例:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# 将运行时目标文件(exe、dll、so等)输出位置设置为/build/bin
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# 将归档文件(lib、a等)输出位置设置为/build/bin
(6)option
定义一个开关。
用法:
option(<variable> "<描述>" [value])
# value的值为ON或OFF,默认为OFF
# 命令行使用cmake命令时,可使用 -D<variable>=ON/OFF 选项来覆盖定义option时的开关状态
会结合下面的configure_file给出使用示例。
(7)configure_file
将输入文件进行替换并生成输出文件。
用法1:
configure_file(<input> <output>)
# input文件中形如@VAR@或${VAR}的字符串会被替换为这些变量的当前值,若未定义则被替换为空字符串。
# 注意:VAR必须在替换命令之前定义。
用法1示例:
将input01.h中的 @PROJECT_VERSION@ 和 ${PROJECT_VERSION} 替换为项目版本号,并将替换后的文件输出为output.h。
input01.h文件:
CMakeLists.txt文件中的写法:
使用cmake -G "MinGW Makefiles" ..\src命令构建完后,会在build目录下生成output.h文件,并且已替换成功:
用法2:
#cmakedefine VAR ...
// 上面的命令会根据VAR是否被set,替换为以下以下两行之一
#define VAR ... // VAR被set
/* #undef VAR */ // VAR未被set
用法2示例:
结合option开关使用,有以下需求:
① 定义开关DATE_ENABLE为OFF状态;
② 若开关为ON状态,则设置DATE变量为20230511;
③ 若设置了DATE变量,则将input01.h中的#cmakedefine DATE 2023替换为#define DATE 2023,并输出到output.h文件中;
input01.h文件:
开关为关的状态,此时输入cmake -G "MinGW Makefiles" ..\src构建,可见output.h中的结果:
在命令中加入-DDATE_ENABLE=ON参数选项将开关设置为开,再构建,可见output.h中的结果:
(8)include_directories
指定所有目标的头文件搜索路径。
用法:
include_directories(dir1 [dir2 ...])
# 将目录dir1、dir2添加到INCLUDE_DIRECTORIES属性中,即编译器的头文件搜索路径;
# 编译时,这些添加的路径会是所有目标的头文件搜索路径。
示例:
比如hello.cpp中想要包含build目录下的func.h头文件:
若未在CMakeLists.txt中指定头文件的搜索路径,则编译链接时会出错,如下:
需要在CMakeLists.txt中让编译器知道头文件的搜索路径在build目录下:
此时再次编译成功:
(9)target_executable_directories
指定某个目标的头文件搜索路径。
用法:
target_include_directories(<target> <INTERFACE|PUBLIC|PRIVATE> <dir1> [<INTERFACE|PUBLIC|PRIVATE> <dir2>] ... )
# 为target目标文件添加搜索路径dir1、dir2;
# 目标文件有INCLUDE_DIRECTORIES和INTERFACE_INCLUDE_DIRECTORIES两个属性
# INCLUDE_DIRECTORIES为对内头文件目录,INTERFACE_INCLUDE_DIRECTORIES为对外头文件目录。
INCLUDE_DIRECTORIES | INTERFACE_INCLUDE_DIRECTORIES | |
---|---|---|
PRIVATE | √ | |
INTERFACE | √ | |
PUBLIC | √ | √ |
示例:
如指定hello目标文件的头文件搜索路径为build:
即可编译成功。
3.3 库的生成和链接
(1)add_subdirectory
添加源文件目录。
用法:
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# source_dir 源文件目录的位置。
# binary_dir 指定编译生成文件存放的位置。
(2)add_library
用指定的源文件生成库。
用法:
add_library(<name> [STATIC|SHARED|MODULE] [EXCLUDE_FROM_ALL] [<source>...])
# STATIC静态库,SHARED动态库。
# 生成库的名字是lib<name>.so或lib<name>.a
(3)target_link_libraries
链接库。
用法:
target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>)
# target 链接入的目标文件,item可以是一个targe,也可以绝对路径。
示例:
如在src目录下有calc子目录,其中的源码是实现加减运算:
则需在CMakeLists.txt中加入如下,表示将calc目录加入生成、编译过程:
在calc目录中也添加CMakeLists.txt文件:
该CMakeLists.txt如下,旨在将加法运算源码生成静态库:
构建并编译:
生成的静态库文件存放于build/calc目录下:
将生成的静态库链接如目标文件,使得目标文件可使用:
生成、编译成功:
动态库只需将STATIC改为SHARED。
区别:
# 指定搜索头文件的路径
include_directories() # 所有
target_include_directories() #单个
# 链接库
link_libraries()
target_link_libraries()
3.4 文件的安装
将可执行文件、库文件、头文件等安装到指定目录。类似于复制。
用法:
install(TARGETS <target> DESTINATION <dir>)
# 安装目标文件
install(FILES <file> DESTINATION <dir>)
# 安装普通文件
install(PROGRAMS <非目标文件的可执行程序(如脚本)> DESTINATION <dir>)
install(DIRECTORY <dir> DESTINATION <dir>)
# 安装目录
示例:
install(TARGET MathFunctions DESTINATION lib) # 安装目标文件
install(FILES MathFunctions.h DESTINATION include) # 安装文件
install(DIRECTORY doc/ DESTINATION d) # 安装目录
命令行用法:
cmake --install . # 将当前目录安装到默认目录
cmake --install . --prefix <dir> # 将当前目录安装到dir目录