2006世界杯巴西

看完这篇文章,我终于搞懂了 CMake,真香!(基础篇)

前言:Makefile 能干的,CMake 干得更优雅

虽然 Makefile是 C/C++ 项目编译的“老司机”,但写起来真的是让人头大。尤其是当项目文件一多,手写依赖就像在搬砖,费时又费力。

那么问题来了,难道我们就没有更优雅的工具了吗?答案是: 有!

这时候,CMake 就像一个专业的项目管家,它会帮你处理所有琐碎的编译细节。你只需要告诉它“我要干什么”,剩下的事情交给它就行了。关键是,它还能 跨平台支持,能帮你生成各种构建系统,比如 Makefile、Visual Studio 工程文件、Xcode 工程,堪称“编译界的瑞士军刀”!

今天我们就从头到尾,用最简单的大白话,把 CMake 的用法讲清楚!看完这篇文章,你一定会觉得:“CMake 原来这么简单!”

在正式开始之前,先通过一张思维导图,帮你快速了解 CMake 的全貌,这样你心里会更有底:

我计划分四篇文章来介绍 cmake,今天只讲 基础篇 部分。

基础篇1. 什么是 CMake?为什么用它?

CMake 是一个跨平台的项目构建工具,通俗点说,它会帮你生成 Makefile 或其他编译系统需要的构建文件。

用 CMake 的好处:

不用手写复杂的 Makefile:你只需要写一个简单的CMakeLists.txt,CMake 会自动帮你生成 Makefile。

支持跨平台开发:不管是 Linux、Windows 还是 MacOS,CMake 都能轻松搞定。

自动化依赖管理:只要源文件有改动,它会自动处理文件依赖,不用你手动维护。

支持大项目:几百个源文件的项目,CMake 比你还细心,编译起来稳得一批。

简单来说,CMake = 省心 + 高效。

2. CMake 的基本使用流程2.1 基本流程

学习 CMake,就像学做饭,只有几个简单步骤:

写菜单:创建一个CMakeLists.txt文件,告诉 CMake 要编译哪些源文件。

配置厨房:运行 CMake,生成构建文件(比如 Makefile)。

开火做饭:用生成的构建文件开始编译,得到程序。

以下是CMake与Makefile的构建流程,帮助你更直观地理解这些步骤:

项目源码

└──► [CMakeLists.txt] # 编写 CMake 构建文件

cmake (命令) # 运行 CMake 命令生成 Makefile

[Makefile] # 自动生成的 Makefile

make (命令) # 使用 Makefile 构建目标

目标文件 # 编译生成的目标文件(如可执行程序或库)

2.2 关键命令

假设你的代码放在项目目录my_project/下,使用 CMake 的流程如下:

mkdir build # 创建编译目录(推荐在项目外部)

cdbuild # 进入编译目录

cmake .. # 生成 Makefile

make # 开始编译

./hello # 运行可执行文件

3. 第一个简单的 CMake 项目3.1 文件结构

我们写一个最简单的项目,只有一个main.cpp文件:

my_project/

├── main.cpp

├── CMakeLists.txt

main.cpp:

#include

intmain{

std::cout<< "Hello, CMake!"<< std::endl;

return0;

}

3.2 编写 CMakeLists.txt

在项目根目录下,新建一个名为CMakeLists.txt的文件,内容如下:

# 指定 CMake 的最低版本

cmake_minimum_required(VERSION 3.10)

# 设置项目名称

project(HelloCMake)

# 添加可执行文件

add_executable(hello main.cpp)

解释:

cmake_minimum_required:告诉 CMake 使用的最低版本,避免版本兼容问题。

project:设置项目名称。

add_executable:告诉 CMake,我们要生成一个名字叫hello的可执行文件,它的源文件是main.cpp。

3.3 编译运行

1、在项目根目录下新建build文件夹,并进入:

mkdir build

cdbuild

2.运行 CMake 配置命令:

cmake ..

此时,CMake 会生成Makefile。

3.执行make开始编译:

make

4.运行生成的程序:

./hello

你会看到输出:

Hello, CMake!

恭喜你,第一个简单的CMake项目完成了!

4. 支持多源文件和目录

当你的项目越来越大,源代码文件越来越多时,你一定会觉得直接在CMakeLists.txt中写一堆文件名特别麻烦。别担心,CMake 给你提供了更优雅的解决方案,让代码管理更简单!

4.1 添加多个源文件

如果你的项目中有多个源文件,像main.cpp和utils.cpp,你可以直接把它们放到add_executable中:

add_executable(hello main.cpp utils.cpp)

这样,CMake 就会把这些文件一起编译成一个可执行文件hello。 简单明了,对吧?

4.2 使用变量管理源文件

但当源文件越来越多时,手动列出每个文件就显得很麻烦。这时候,我们可以用变量来管理这些文件,CMake 会帮你搞定。

set(SOURCES main.cpp utils.cpp)

add_executable(hello ${SOURCES})

通过这种方式,你可以轻松管理文件列表,未来如果需要增加或删除文件,只需要修改这个变量,就能一劳永逸。

是不是很方便?

除了自己定义的变量,CMake 还可以访问系统环境变量。例如,获取当前用户的HOME目录:

set(MY_PATH $ENV{HOME})

CMake 提供了$ENV{ }语法,用于访问系统的环境变量,通过$ENV{HOME},CMake 会自动读取你系统中的HOME环境变量,把它的值赋给MY_PATH变量。

4.3 多目录管理

随着项目逐渐变大,你的代码可能会分散到多个目录中。比如,你可能会有一个src/目录存放核心代码,一个include/目录存放头文件,还有一个libs/目录存放外部库的文件。

到了这个阶段,你可能不希望将所有文件都写在一个 CMakeLists.txt 文件里了。没错,CMake 完全支持这种方式,允许你轻松管理多个目录的代码。

使用 cmake 来管理项目,目录结构一般是这样:

my_project/

├── CMakeLists.txt # 根目录的 CMake配置

├── src/

│ ├── CMakeLists.txt # src 目录下的 CMake 配置

│ ├── main.cpp

│ ├── utils.cpp

│ └── helper.cpp

├── libs/

│ ├── CMakeLists.txt # libs 目录下的 CMake 配置

│ ├── lib.cpp

│ └── lib.h

├── include/

│ ├── utils.h

│ └── helper.h

└── build/ # 构建目录(自动创建)

在这个结构中,根目录下有一个CMakeLists.txt文件,它负责管理整个项目。而src/和libs/目录下分别有各自的CMakeLists.txt文件,用来管理这些目录中的源文件和库。这样,不仅让项目更有条理,而且也方便管理。

1、根目录的 CMakeLists.txt

在根目录的CMakeLists.txt文件中,我们通常做一些全局的配置,比如设置项目的名字、指定 CMake 最低版本要求,以及引入子目录等。

# 根目录的 CMakeLists.txt

# 设置项目名和 CMake 最低版本

cmake_minimum_required(VERSION 3.10)

project(MyProject)

# 添加 src 和 libs 子目录

add_subdirectory(src)

add_subdirectory(libs)

这里做了两件事:

使用add_subdirectory告诉 CMake 去处理src/和libs/子目录的CMakeLists.txt文件。

设置项目名为MyProject,并指定了最低版本要求(3.10)。

2、src/ 目录的 CMakeLists.txt

接下来,在src/目录下的CMakeLists.txt文件中,负责编译src/目录下的源文件(比如main.cpp和utils.cpp)。如果有多个源文件,你可以通过变量来管理这些文件。

# src/CMakeLists.txt

# 设置源文件

set(SOURCES

main.cpp

utils.cpp

helper.cpp

)

# 创建可执行文件

add_executable(hello ${SOURCES})

# 设置头文件路径

target_include_directories(hello PRIVATE ${PROJECT_SOURCE_DIR}/include)

# PROJECT_SOURCE_DIR:这是一个 CMake 内置的变量,表示项目的源代码根目录。

# 无论你在哪个子目录中,它都会指向项目的最外层目录:即 my_project/

# 链接库

target_link_libraries(hello PRIVATE mylib)

这段代码做了几件事:

使用set(SOURCES ...)将src/目录下的源文件名赋值给变量 SOURCES,方便下面使用。

使用add_executable创建可执行文件hello。

使用target_include_directories设置头文件路径,指向根目录下的include/目录,这样编译器就能找到头文件。

使用target_link_libraries链接一个外部库mylib(假设它在libs/目录下)。

3、libs/ 目录的 CMakeLists.txt

libs/目录下的CMakeLists.txt文件类似地负责编译库文件。

# libs/CMakeLists.txt

# 设置库文件源代码

set(LIB_SOURCES

lib.cpp

)

# 创建静态库

add_library(mylib STATIC ${LIB_SOURCES}) # STATIC 可改为 SHARED 生成动态库

# 设置头文件路径

target_include_directories(mylib PUBLIC ${PROJECT_SOURCE_DIR}/include)

在这里:

使用set(LIB_SOURCES ...)设置变量 LIB_SOURCES,将libs/目录下的源文件名赋值给它。

使用add_library创建了一个静态库mylib。

使用target_include_directories设置库的头文件路径,指向根目录下的include/目录,通过 PUBLIC 关键字,确保其他需要引用mylib的目标能够找到头文件。

4、项目根目录的头文件(include/)

在include/目录下存放了项目的头文件。需要注意的是,你不需要在src/和libs/的 CMakeLists.txt 文件中列出这些头文件。

CMake 会自动知道你从include/目录中包含头文件,只要你确保src/和libs/目录下的 CMakeLists.txt 文件中正确配置了target_include_directories。

my_project/

├── include/

│ ├── utils.h

│ └── helper.h

5、添加build/目录

到这里,你的代码管理已经非常清晰了,但接下来,我们需要谈一谈build/目录。build/目录是构建过程中的输出目录,它将存放所有编译产生的中间文件、目标文件和最终的可执行文件。

通常,在 CMake 构建项目时,我们不会直接在源码目录下运行构建命令,而是会创建一个单独的build/目录,这样可以保持源码目录的整洁,同时也可以更方便地管理构建文件。你可以这样做:

创建build/目录:

在项目根目录下创建一个build/目录:

mkdir build

cdbuild

配置项目:

然后在build/目录下运行cmake命令,CMake 会自动查找根目录下的CMakeLists.txt文件并配置整个项目。

cmake ..

这样,CMake 会根据根目录的CMakeLists.txt配置生成必要的构建文件。

开始构建:

配置完成后,你可以运行make或其他构建工具来进行编译:

make

构建输出:

编译完成后,所有生成的文件(比如目标文件、可执行文件等)都会被放到build/目录里。源代码目录就不会被任何临时文件污染了,保持整洁。

小结:

通过这种结构和配置方式,CMake 可以非常有效地管理多个目录下的源代码和库:

根目录的CMakeLists.txt负责引入子目录和进行全局配置。

每个子目录(如src/和libs/)都有自己的CMakeLists.txt来管理该目录下的源文件和库。

target_include_directories确保头文件可以被正确引用。

build/目录用来存放所有构建过程中生成的中间文件和最终的可执行文件,保持源代码目录干净整洁。

这种多目录的管理方式,会让你的项目变得更加模块化、易于扩展,同时也方便多人协作开发。如果以后需要添加新的库或源文件,只需在对应子目录的CMakeLists.txt中做调整,而根目录只需要引入子目录即可。

友情提醒:返回搜狐,查看更多

Copyright © 2088 世界杯预选赛南美_决赛世界杯 - scbfjc.com All Rights Reserved.
友情链接