CMake基础:构建流程详解

news2025/6/12 22:15:27

目录

1.CMake构建过程的基本流程

2.CMake构建的具体步骤

2.1.创建构建目录

2.2.使用 CMake 生成构建文件

2.3.编译和构建

2.4.清理构建文件

2.5.重新配置和构建

3.跨平台构建示例

4.工具链与交叉编译

5.CMake构建后的项目结构解析

5.1.CMake构建后的目录结构

5.2.构建生成的文件类型及其作用

5.3.CMakeLists.txt与生成的Makefile的关系

6.完整示例项目

7.总结


1.CMake构建过程的基本流程

CMake的构建过程可以分为三个主要步骤:配置(Configuration)、生成(Generation)和构建(Build)。下面我们将详细解析每个步骤。

1.配置(Configuration)

        配置阶段是CMake解析CMakeLists.txt文件的过程。在这个阶段,CMake会读取CMakeLists.txt文件,并执行其中的命令。这些命令主要用于检查系统环境(例如编译器、库等),设置构建选项,以及定义构建目标(例如库、可执行文件等)。

        CMakeLists.txt文件是CMake的核心,它定义了项目的构建规则和依赖关系。每个目录(包括子目录)中都可以有一个CMakeLists.txt文件。在配置阶段,CMake会从顶层目录的CMakeLists.txt文件开始,递归地处理每个子目录中的CMakeLists.txt文件。

2.生成(Generation)

        生成阶段是CMake根据配置阶段的结果,生成实际的构建文件的过程。这些构建文件通常是Makefile文件,但也可以是其他类型的构建文件,例如Ninja构建文件,或者Visual Studio项目文件,这取决于你选择的构建工具。

        在生成阶段,CMake会将CMakeLists.txt文件中定义的构建规则和依赖关系,转换为构建工具可以理解的形式。例如,如果你选择的构建工具是Make,CMake会生成Makefile文件。每个目录(包括子目录)中都会生成一个Makefile文件。

3.构建(Build)

        构建阶段是使用构建工具(例如Make、Ninja或Visual Studio)根据生成的构建文件,编译源代码并链接生成目标文件的过程。

        在构建阶段,构建工具会读取生成的构建文件,按照其中定义的规则和依赖关系,执行实际的编译和链接操作。构建工具会自动处理依赖关系,确保在编译和链接一个目标文件之前,其所有依赖的目标文件都已经被正确地编译和链接。

2.CMake构建的具体步骤

CMake 的构建流程分为几个主要步骤,从设置项目到生成和执行构建命令。

  1. 创建构建目录:保持源代码目录整洁。
  2. 使用 CMake 生成构建文件:配置项目并生成适合平台的构建文件。
  3. 编译和构建:使用生成的构建文件执行编译和构建。
  4. 清理构建文件:删除中间文件和目标文件。
  5. 重新配置和构建:处理项目设置的更改。

以下是详细的构建流程说明:

2.1.创建构建目录

CMake 推荐使用 "Out-of-source" 构建方式,即将构建文件放在源代码目录之外的独立目录中。这样可以保持源代码目录的整洁,并方便管理不同的构建配置。

创建构建目录:在项目的根目录下,创建一个新的构建目录。例如,可以创建一个名为 build 的目录。

mkdir build

进入构建目录:进入刚刚创建的构建目录。

cd build

2.2.使用 CMake 生成构建文件

        在构建目录中运行 CMake,以生成适合当前平台的构建系统文件(例如 Makefile、Ninja 构建文件、Visual Studio 工程文件等)。

        运行 CMake 配置:在构建目录中运行 CMake 命令,指定源代码目录。源代码目录是包含 CMakeLists.txt 文件的目录。

cmake ..

如果需要指定生成器(如 Ninja、Visual Studio),可以使用 -G 选项。例如:

cmake -G "Ninja" ..

如果需要指定构建类型(如 Debug 或 Release),可以使用 -DCMAKE_BUILD_TYPE 选项。例如:

cmake -DCMAKE_BUILD_TYPE=Release ..

检查配置结果:CMake 会输出配置过程中的详细信息,包括找到的库、定义的选项等,如果没有错误,构建系统文件将被生成到构建目录中。

2.3.编译和构建

使用生成的构建文件进行编译和构建。

不同的构建系统使用不同的命令。

使用 Makefile(或类似构建系统):如果使用 Makefile,可以运行 make 命令来编译和构建项目。

make

如果要构建特定的目标,可以指定目标名称。例如:

make MyExecutable

使用 Ninja:如果使用 Ninja 构建系统,运行 ninja 命令来编译和构建项目。

ninja

与 make 类似,可以构建特定的目标:

ninja MyExecutable

使用 Visual Studio:如果生成了 Visual Studio 工程文件,可以打开 .sln 文件,然后在 Visual Studio 中选择构建解决方案。

也可以使用 msbuild 命令行工具来编译:

msbuild MyProject.sln /p:Configuration=Release

2.4.清理构建文件

构建过程中生成的中间文件和目标文件可以通过清理操作删除。

使用 Makefile:运行 make clean 命令(如果定义了清理规则)来删除生成的文件。

make clean

使用 Ninja:运行 ninja clean 命令(如果定义了清理规则)来删除生成的文件。

ninja clean

手动删除:可以手动删除构建目录中的所有文件,但保留源代码目录不变。例如:

rm -rf build/*

2.5.重新配置和构建

如果修改了 CMakeLists.txt 文件或项目设置,可能需要重新配置和构建项目。

重新运行 CMake 配置:在构建目录中重新运行 CMake 配置命令。

cmake ..

重新编译:使用构建命令重新编译项目。

make

3.跨平台构建示例

1.Linux/macOS(CMake + Make)

# 配置构建环境
mkdir build && cd build
cmake ..  # 默认生成 Makefile

# 编译
make -j$(nproc)  # 并行编译(nproc 获取 CPU 核心数)

# 安装
make install

2.Windows(CMake + Ninja)

# 配置构建环境(使用 Ninja 加速)
mkdir build && cd build
cmake -G Ninja ..

# 编译
ninja

# 安装
ninja install

3.Windows(CMake + MSVC)

# 生成 Visual Studio 项目
mkdir build && cd build
cmake -G "Visual Studio 17 2022" ..

# 编译(使用 MSBuild)
cmake --build . --config Release

# 或直接打开 .sln 文件用 Visual Studio 编译
start my_project.sln

4.工具链与交叉编译

1.指定工具链文件

创建 qt_mingw_toolchain.cmake 文件:

# qt_mingw_toolchain.cmake
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER "C:/Qt/Qt5.15.2/mingw81_64/bin/gcc.exe")
set(CMAKE_CXX_COMPILER "C:/Qt/Qt5.15.2/mingw81_64/bin/g++.exe")
set(CMAKE_RC_COMPILER "C:/Qt/Qt5.15.2/mingw81_64/bin/windres.exe")

# 设置 Qt 路径
set(Qt5_DIR "C:/Qt/Qt5.15.2/mingw81_64/lib/cmake/Qt5")

# 防止 CMake 寻找 Windows 系统库
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
#cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=../toolchain-arm.cmake
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=../qt_mingw_toolchain.cmake

2.工具链文件示例(arm-linux-gnueabihf)

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

# 指定交叉编译工具
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

# 指定系统根目录
set(CMAKE_FIND_ROOT_PATH /path/to/arm-rootfs)

# 仅在根目录查找依赖
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

5.CMake构建后的项目结构解析

5.1.CMake构建后的目录结构

CMake构建完成后,会在项目的根目录下生成一个名为build的目录。这个目录是CMake构建过程中所有中间文件和最终生成的目标文件的存放地。下面我们将详细解析这个目录的结构。

首先,我们来看一下build目录的一级子目录:

  • CMakeFiles:这个目录中存放的是CMake在构建过程中生成的临时文件,包括编译器检查的结果、Find模块(Find Modules)查找的结果等。这些文件主要用于CMake自身的需求,一般情况下,我们不需要关注这个目录的内容。
  • Testing:如果你的项目中包含了CTest测试,那么这个目录将会被生成。它包含了所有CTest测试的结果。
  • bin:这个目录中包含了所有的可执行文件(Executable Files)。如果你的CMake项目中包含了多个可执行文件,那么它们都会被放在这个目录中。
  • lib:这个目录中包含了所有的库文件(Library Files)。无论是静态库(Static Libraries)还是动态库(Dynamic Libraries),都会被放在这个目录中。

接下来,我们再深入到CMakeFiles目录中,看一下它的二级子目录:

  • project.dir:这个目录中包含了项目构建过程中的临时文件,如.o文件和.d文件。这些文件是编译器在编译源代码时生成的。
  • CMakeOutput.log:这个文件记录了CMake在配置过程中的输出信息,包括编译器检查的结果、Find模块查找的结果等。
  • CMakeError.log:这个文件记录了CMake在配置过程中遇到的错误信息。

以上就是CMake构建后的目录结构的基本情况。在实际的项目中,可能会根据项目的具体需求,生成更多的子目录和文件。但是,这些基本的目录和文件是你在任何一个使用CMake构建的项目中都能看到的。

5.2.构建生成的文件类型及其作用

CMake构建过程中会生成多种类型的文件,每种文件都有其特定的作用。下面我们将详细解析这些文件的类型和作用。

  • CMakeFiles目录:这个目录中存放的是CMake在构建过程中生成的临时文件,包括编译器检查的结果、Find模块(Find Modules)查找的结果等。这些文件主要用于CMake自身的需求,一般情况下,我们不需要关注这个目录的内容。
  • project.dir目录:这个目录中包含了项目构建过程中的临时文件,如.o文件和.d文件。这些文件是编译器在编译源代码时生成的。
  • CMakeOutput.log文件:这个文件记录了CMake在配置过程中的输出信息,包括编译器检查的结果、Find模块查找的结果等。
  • CMakeError.log文件:这个文件记录了CMake在配置过程中遇到的错误信息。
  • Testing目录:如果你的项目中包含了CTest测试,那么这个目录将会被生成。它包含了所有CTest测试的结果。
  • bin目录:这个目录中包含了所有的可执行文件(Executable Files)。如果你的CMake项目中包含了多个可执行文件,那么它们都会被放在这个目录中。
  • lib目录:这个目录中包含了所有的库文件(Library Files)。无论是静态库(Static Libraries)还是动态库(Dynamic Libraries),都会被放在这个目录中。

以上就是CMake构建过程中生成的主要文件类型及其作用。理解这些文件的作用,可以帮助我们更好地理解CMake的构建过程。

5.3.CMakeLists.txt与生成的Makefile的关系

        在CMake构建系统中,CMakeLists.txt文件和生成的Makefile文件之间存在着密切的关系。下面我们将详细解析这种关系。

        CMakeLists.txt是CMake构建系统的核心文件,它定义了项目的构建规则和依赖关系。在执行CMake命令时,CMake会读取CMakeLists.txt文件,解析其中的构建规则和依赖关系,然后生成相应的Makefile文件。

        Makefile文件是由CMake根据CMakeLists.txt文件生成的,它是Make构建工具可以直接读取的构建脚本。Makefile文件中包含了具体的编译命令和链接命令,以及源文件和目标文件之间的依赖关系。

        在一个CMake项目中,通常会有多个CMakeLists.txt文件,每个目录下都可以有一个CMakeLists.txt文件。这些CMakeLists.txt文件中定义的构建规则和依赖关系,会被CMake合并到一起,生成一个或多个Makefile文件。

        如果一个CMake项目中只有一个CMakeLists.txt文件,那么CMake会生成一个Makefile文件。如果一个CMake项目中有多个CMakeLists.txt文件,那么CMake会在每个CMakeLists.txt文件所在的目录下生成一个Makefile文件。这些Makefile文件中,顶层目录下的Makefile文件是主Makefile文件,它会调用其他目录下的Makefile文件。

        总的来说,CMakeLists.txt文件和生成的Makefile文件之间的关系是:CMakeLists.txt文件定义了项目的构建规则和依赖关系,CMake根据CMakeLists.txt文件生成Makefile文件,然后Make根据Makefile文件执行具体的构建任务。

6.完整示例项目

1.项目结构

my_project/
├── CMakeLists.txt
├── src/
│   ├── main.cpp
│   └── lib/
│       ├── utils.cpp
│       └── utils.h
└── tests/
    └── test_main.cpp

2.CMakeLists.txt 示例

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0.0)

# 添加可执行文件
add_executable(my_app src/main.cpp src/lib/utils.cpp)

# 设置 C++ 标准
set_target_properties(my_app PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
)

# 添加测试(可选)
if(ENABLE_TESTING)
    enable_testing()
    add_executable(my_test tests/test_main.cpp src/lib/utils.cpp)
    add_test(NAME MyTest COMMAND my_test)
endif()

# 安装规则
install(TARGETS my_app DESTINATION bin)

3.构建命令

# 配置并编译(Debug 模式)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_TESTING=ON
cmake --build build

# 运行测试
ctest --test-dir build

# 安装到 /usr/local
sudo cmake --install build

7.总结

        CMake的构建一个很复杂的工程,根据平台的不同构建规则和过程有所不同,CMake屏蔽了底层的实现差异,但是还是要去了解和熟悉,这会让我们在日后的使用过程当中少出差错,即便出了问题,也有助于我们很快的找到问题,很快的解决它。

相关链接

  • CMake 官网 CMake - Upgrade Your Software Build System
  • CMake 官方文档:CMake Tutorial — CMake 4.0.2 Documentation
  • CMake 源码:https://github.com/Kitware/CMake
  • CMake 源码:CMake · GitLab
  • 中文版基础介绍: CMake 入门实战 | HaHack
  • wiki:Home · Wiki · CMake / Community · GitLab

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2407811.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…

使用分级同态加密防御梯度泄漏

抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…

【JVM】- 内存结构

引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…