前言:因为工作需要开发嵌入式桌面应用,因此入坑C++开发。因为之前在NDK的时候接触过c++,了解些基本语法,想着编程语言大部分都是类似的。因此边开发边学习。但是在开发过程中,发现环境配置,编译,等过程有时候耗费时间还挺多的,比如编译时找不到文件,链接时又找不到库,好不容易编译好了,运行还找不到库。命令行运行UI程序还的设置DISPLAY变量等等。因此系统的学习下CMakeList知识。
CMake是什么
CMake是一个开源、跨平台的编译、测试和打包工具,它使用比较简单的语言描述编译、安装的过程,输出Makefile或者project文件,再去执行构建。类似android里面的Gradle
CMakeLists.txt配置信息
一个简单项目的最基本CMakeLists.txt配置信息如下:
# 设置Cmake版本
cmake_minimum_required(VERSION 3.16)
# 设置项目名称
project(c_demo)
# 设置C++版本
set(CMAKE_CXX_STANDARD 17)
# 设置编译文件
add_executable(c_demo src/main.cpp)
该项目只有一个cpp文件main.cpp。文件也是一个简单的hello world打印
#include <iostream>
int main(int argc,char *argv[]){
std::cout<<"hello world"<<std::endl;
return 0;
}
项目和配置准备好了,接下来进行编译和构建。
cmake -B build
生成build目录
cmake -B build
-- Configuring done
-- Generating done
-- Build files have been written to: /xxx/project/c-demo/build
cmake —build
再执行—build命令,build表示目录,-j2表示使用2个线程
cmake --build build -j2
[2/2] Linking CXX executable c_demo
上面命令执行完后,在build目录下回生成一个可执行程序c_demo. 直接运行程序
./build/c_demo
hello world
一个项目从配置到编译到运行的整个流程完成。
解读配置
cmake_minimum_required 语法
# 设置Cmake版本
cmake_minimum_required(VERSION major.minor[.patch[.tweak]])
VERSION
:关键字,表示后面跟着的是版本号。major.minor[.patch[.tweak]]
:版本号,由主版本号、次版本号组成,可选地包括补丁号和微调号。例如,3.10
、3.10.2
。
用于指定当前项目所需的最低cmake版本。** cmake_minimum_required
指令必须出现在 CMakeLists.txt 文件的最顶部 **
CMake 在处理项目之前,会首先检查当前安装的 CMake 版本是否满足 cmake_minimum_required
指定的最低版本要求。如果安装的版本低于指定版本,CMake 会报错并停止处理
project语法
project(<PROJECT-NAME> [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[LANGUAGES <language1> [<language2> ...]])
<PROJECT-NAME>
:项目的名称,这是必需的参数。VERSION
:指定项目的版本号,这是可选的。版本号由主版本号、次版本号、补丁号和微调号组成,其中主版本号和次版本号是必需的,补丁号和微调号是可选的。LANGUAGES
:指定项目使用的编程语言,这也是可选的。CMake 支持多种编程语言,包括 C、C++、Fortran、Java、Objective-C、Objective-C++ 等。如果未指定LANGUAGES
参数,CMake 将默认启用 C 和 C++。
set 语法
set(<variable> <value> [PARENT_SCOPE])
在 CMake 中,set
命令用于定义或修改变量 set(CMAKE_CXX_STANDARD 17)
这条指令将 CMake 变量 CMAKE_CXX_STANDARD
的值设置为 17
,意味着告诉 CMake 在构建过程中使用 C++17 标准进行编译。
与编译器兼容性
- CMake 在设置
CMAKE_CXX_STANDARD
后,会尝试配置编译器以使用指定的标准版本。 - 如果编译器不支持指定的标准版本,CMake 可能会尝试使用较低的兼容版本进行编译。但是,如果同时设置了
CMAKE_CXX_STANDARD_REQUIRED
为ON
,则编译器必须支持指定的标准版本,否则 CMake 会报错并停止构建过程。
set还可以设置一个列表变量
set(<variable> [<value1> <value2> ...])
例如
set(MY_LIST "value1" "value2" "value3")
在这里,MY_LIST
变量现在包含了一个有三个元素的列表。
set还可以设置缓存变量,环境变量。后续学习CMake详细语法的再示范。
add_executeable语法
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2] ...)
<name>
:可执行文件目标的名称。在这个例子中,c_demo
是可执行文件的名称。[WIN32]
:可选参数,用于在 Windows 系统下创建一个以 WinMain 为入口的可执行文件(通常入口函数为 main 的程序是一个控制台应用程序,而使用 WIN32 选项则创建一个 GUI 应用程序)。[MACOSX_BUNDLE]
:可选参数,用于 macOS 或 iOS 系统下创建一个 GUI 可执行应用程序。[EXCLUDE_FROM_ALL]
:可选参数,用于指定该可执行文件目标是否会被默认构建。如果使用了这个选项,该目标在默认构建时不会被构建,需要手动指定构建。[source1] [source2] ...
:构建可执行文件所需的源文件列表。在这个例子中,src/main.cpp
是唯一的源文件。
作用
add_executable
指令告诉 CMake 构建系统,使用指定的源文件(在这个例子中是 src/main.cpp
)来构建一个名为 c_demo
的可执行文件。CMake 会处理这些源文件,调用适当的编译器和链接器,生成最终的可执行文件
编译构建命令详细介绍
cmake -B
是CMake 构建系统中的一个常用命令行指令,用于在指定目录下生成构建系统所需的文件。 基本语法
cmake -B <build-directory> [options]
- B :指定构建目录(build directory)。CMake 将会在这个目录中生成构建系统所需的文件,如 Makefile、project 文件等。 是你希望 CMake 创建并使用的构建目录的路径。
[options]
:其他可选的 CMake 命令行选项,如-S
(指定源代码目录)、-D
(定义 CMake 变量)等。
在 cmake -B build 的情况下, 被设置为 build,意味着 CMake 将在当前目录下的 build 文件夹中生成构建文件。 这个过程通常被称为“配置阶段”(configure stage)。在这一阶段,CMake 会读取 CMakeLists.txt 文件(以及可能包含的其他 CMake 文件),并根据其中的指令生成适用于特定平台的构建系统文件。
注意事项
构建目录与源代码目录分离:使用 -B 选项将构建目录与源代码目录分离是一个最佳实践。这有助于保持源代码目录的清洁,并使得构建过程更加灵活和可重复。
CMakeLists.txt 文件:确保 CMakeLists.txt 文件正确配置了项目的构建规则、依赖关系等。这是 CMake 生成正确构建文件的关键。
生成器:CMake 支持多种生成器,用于生成适用于不同平台和构建系统的文件。在大多数情况下,CMake 会自动选择合适的生成器,但你也可以使用 -G 选项指定特定的生成器(如 Ninja、Unix Makefiles 等)。
缓存变量:在配置阶段,你可以使用 -D 选项设置缓存变量。这些变量在后续的构建过程中可以被引用和修改。例如,cmake -B build -DCMAKE_BUILD_TYPE=Release 会设置构建类型为发布模式。
cmake --build 命令
是 CMake 提供的一个核心功能,它允许开发者使用单一的命令行接口来调用不同的构建系统(如 Make、Ninja、Visual Studio 等),从而构建项目。这个命令极大地简化了跨平台构建过程,并确保了不同环境下的构建一致性。以下是对 cmake --build 命令的详细介绍: 一、基本语法
cmake --build <build-directory> [options]
:指向包含生成的构建系统文件(如 Makefile 或 *.sln 文件)的目录,这通常是在运行 cmake 命令时指定的构建目录。 [options]:可选的参数,用来控制构建过程的具体行为。
二、常用选项
--config <config-name>:用于指定构建配置。这在使用支持多配置的生成器(如 Visual Studio)时特别有用。常见的配置包括 Debug、Release、MinSizeRel 和 RelWithDebInfo。
--target <target-name>:允许指定单一或多个目标来构建,而不是构建整个项目。这可以显著减少构建时间,尤其是在大型项目中。
--parallel [<jobs>] 或 -j [<jobs>]:允许并行构建,可以显著加快构建过程。<jobs> 参数指定同时运行的作业数。如果省略 <jobs>,CMake 将尝试自动确定最优的作业数。
--verbose:提供更多的构建过程输出,对于调试构建问题非常有帮助。
总结
project
指令让我们能够定义项目的名称、版本以及所使用的编程语言,其中版本号和编程语言的指定都是可选的,未指定编程语言时 CMake 会默认启用 C 和 C++。
set
命令在 CMake 中非常强大,不仅可以用于定义或修改变量,还能设置列表变量,同时还能涉及缓存变量和环境变量的设置,在设置 C++ 编译标准时要注意编译器的兼容性,通过合理设置 CMAKE_CXX_STANDARD_REQUIRED
可以确保编译器必须支持指定的标准版本。
而 add_executable
指令则是构建可执行文件的关键,它允许我们指定可执行文件的名称以及所需的源文件,还包含一些可选参数用于满足不同平台和构建需求。通过理解和掌握这些基本语法,我们可以初步构建一个简单的 CMake 项目,为后续更深入的学习和复杂项目的开发打下坚实的基础。后续我们还将继续深入学习 CMake 的详细语法和高级特性