CMake构建和调试简单程序(windows)
一 构建简单程序
1 创建项目文件结构
新建一个项目文件夹(例如 HelloWorld
),内部包含两个核心文件:
- 源代码文件:main.cpp
- CMake配置文件:CMakeLists.txt(告诉CMake如何构建项目)
文件结构如下:
2 编写源代码
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>int main(int argc, char* argv[])
{if (argc < 2) {std::cout << "Usage: " << argv[0] << " number" << std::endl;return 1;}// 将输入转为double类型const double inputValue = atof(argv[1]);// 计算输入数据的平方根const double outputValue = sqrt(inputValue);std::cout << "The square root of " << inputValue<< " is " << outputValue<< std::endl;return 0;
}
3 编写 CMake 配置文件(CMakeLists.txt)
# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)# set the project name
project(Hello)# add the executable
add_executable(Hello main.cpp)
4 执行 CMake 生成构建文件(外部构建推荐)
CMake 的核心作用是 根据配置文件生成对应平台的构建文件(例如 Linux 的 Makefile、Windows 的 Visual Studio 解决方案、macOS 的 Xcode 项目)。
推荐使用「外部构建」(在源文件外创建 build 文件夹),避免构建文件污染源目录。
步骤如下,进入到HelloWorld文件夹,打开cmd,输入以下命令
mkdir build # 创建构建目录
cd build # 进入构建目录
cmake .. -G "Visual Studio 17 2022" # 在 build 目录下,执行 cmake ..(.. 表示引用上级目录 # 的 CMakeLists.txt),对应 VS2022
执行完上述命令后,会生成SLN(Visual Studio 解决方案)和vcxproj(项目文件),bulid文件夹内容如下:
CMake 在 Windows 生成 Visual Studio 解决方案时,会自动创建 3 个辅助目标(非可执行):
ALL_BUILD
:编译解决方案中所有的项目(包括可执行目标 + 其他辅助目标);ZERO_CHECK
:检查 CMakeLists.txt 是否有修改,若修改则自动重新生成构建文件;INSTALL
:(可选)用于安装编译产物(如将可执行文件复制到指定目录)。
这三个目标都没有实际的可执行代码,仅用于 “管理构建流程”,因此无法作为调试入口 —— 调试必须指向写的可执行目标(比如 hello
,对应 hello.exe
)。
5 编译项目(生成可执行文件)
根据步骤 4 生成的构建文件,执行编译命令:
1 使用vs2022,直接打开 build 目录下的 HelloWorld.sln,在 Visual Studio 中点击「生成」→「生成解决方案」
2 使用cmd,命令如下
cmake --build . # --build 指定编译生成的文件存放目录(包括可执行文件) . 表示存放到当前目录
6 运行程序
编译成功后,cd到可执行文件所在的目录,执行
.\hello 5 # 5是输入数字,
关键说明:
执行 CMake 生成构建文件的阶段不会调试源文件中的代码,甚至不会接触到源文件的代码逻辑 —— 这个阶段的核心作用是「根据 CMakeLists.txt 配置规则,生成对应平台的构建脚本(如 Linux 的 Makefile、Windows 的 Visual Studio 解决方案)」,本质是「搭建编译流程的框架」,而非「执行或编译代码」。
完整流程:
CMake 生成构建文件
→ 编译生成可执行文件(需开启 Debug 模式)
→ 用调试工具(GDB/VS 调试器等)加载可执行文件并调试代码
1. CMake 生成构建文件阶段:完全不检查代码错误
这个阶段的核心是 “解析 CMakeLists.txt 的配置规则”,比如确认 “要编译的源文件路径是否存在”“指定的构建类型(Debug/Release)是否合法”,但不会读取源文件(如 main.cpp)的具体代码内容—— 哪怕代码里有明显的语法错误(比如把 std::cout
写成 std:cout
),CMake 也完全感知不到,照样能生成构建文件(如 Makefile、VS 解决方案)。
举个例子:如果 main.cpp
里写了 std:cout << "Hello"
(少了一个冒号,语法错误),执行 cmake ..
时依然会成功生成 Makefile,因为 CMake 只关心 “有 main.cpp 这个文件”,不关心文件里写了什么。
2. 编译生成可执行文件阶段:会检查语法错误,发现错误会报错
当执行 make
(Linux/macOS)或在 VS 中点击 “生成” 时,编译器(如 GCC、Clang、MSVC)会逐行解析源文件的代码,此时会严格检查代码的 “语法正确性” 和 “基础编译规则”,常见错误都会被发现并报错:
- 语法错误:比如少分号、括号不匹配、关键字拼写错误(如
int
写成Int
); - 编译规则错误:比如变量未定义、函数参数不匹配、头文件未包含(如用了
std::cout
却没写#include <iostream>
); - 类型错误:比如把字符串赋值给整型变量、函数返回值类型不匹配等。
需要注意的是,编译阶段只能检查 “语法 / 编译规则错误”,无法发现 “逻辑错误”
3. 加载可执行文件
调试工具会读取源文件的代码、设置断点、单步执行等,检查逻辑错误。
二 调试CMake构建的简单程序
在使用 CMake 构建的项目中调试源代码,核心是生成带调试信息的可执行文件,再通过对应平台的调试工具(如 GDB、LLDB、Visual Studio 调试器)进行断点、单步执行、变量查看等操作。
1 核心前提:配置 CMake 生成调试信息
调试的关键是让编译器生成「调试符号」(记录源代码与二进制文件的对应关系,帮助调试工具定位代码行、变量)。通过 CMake 指定 Debug
构建类型即可自动开启调试信息,无需手动写编译器参数(如 GCC 的 -g
)。
方式 1:临时指定 Debug 模式(推荐,不污染配置文件)
在「生成构建文件」时,通过 -DCMAKE_BUILD_TYPE=Debug
临时设置,步骤如下:
cmake .. -G "Visual Studio 17 2022" -DCMAKE_BUILD_TYPE=Debug
方式 2:固定配置 Debug 模式(适合长期调试)
直接在 CMakeLists.txt
中添加配置,无需每次执行 CMake 时传参数:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)# set the project name
project(Hello)# 固定设置为 Debug 模式,生成调试符号
set(CMAKE_BUILD_TYPE Debug)# add the executable
add_executable(Hello main.cpp)
之后正常执行 cmake ..
即可生成带调试信息的构建文件。
2 编译生成带调试信息的可执行文件
配置完成后,执行编译命令,生成包含调试符号的可执行文件(若代码有语法错误,此阶段会报错,需先修复):
打开
build
目录下的HelloWorld.sln
解决方案;顶部菜单栏选择「解决方案配置」为
Debug
(确保是调试模式);点击「生成」→「生成 hello」,或按
Ctrl+Shift+B
,生成hello.exe
(路径:build/Debug/hello.exe
)
3 分平台进行代码调试
说明:
1 调试后修改的代码需要重新CMake吗
调试后仅修改代码逻辑(如修改 main.cpp
中的输出内容、调整变量值、修复逻辑错误等),不需要重新执行 CMake 生成构建文件;只需重新编译即可,编译工具会自动识别源文件的修改,无需重新生成构建文件。
核心原因:CMake 与编译工具的分工不同
CMake:仅负责「生成构建文件」(如 Makefile、Visual Studio 解决方案),本质是定义「编译规则」(比如 “要编译哪些文件”“用什么选项编译”“生成哪个可执行文件”)。一旦构建文件生成,只要编译规则不变,CMake 就无需再运行。
编译工具(如
make
、Visual Studio 编译器):根据 CMake 生成的「构建文件」,检测源文件的修改状态(通过文件修改时间判断),仅重新编译「被修改过的源文件」,最终生成可执行文件。
只有当修改了「影响构建配置的内容」(如新增源文件、修改 CMakeLists.txt
、变更依赖库等)时,才需要重新执行 CMake。
2 调试时报错,无法启动程序“\build\x64\Debug\ALL_BUILD”
原因是:将 CMake 自动生成的 ALL_BUILD
目标设为了调试启动项,但 ALL_BUILD
并非可执行文件 —— 它是 CMake 生成的 “辅助构建目标”,仅用于触发所有项目的编译,本身没有可执行代码,因此无法启动调试。
解决方法:将 “实际可执行目标” 设为调试启动项。可执行目标:是在 CMakeLists.txt
中用 add_executable
定义的名称(比如 hello
,图标是 “控制台应用” 或 “exe” 样式)。