VSCode中的CMake编译与调试的基本配置
先介绍如何在VSCode中编写CMakeLists.txt以实现C++代码的多文件编译,然后介绍如何编写launch.json和tasks.json文件以实现代码的调试
VSCode中的CMake编译与调试的基本配置
一、环境配置
1.1 VSCode安装
- 略
1.2 MinGW安装
- 记得配置环境变量即可,略
1.3 CMake安装
- 官方下载网址在此,若下载免安装的
.zip
版本则可直接解压到某处,然后配置环境变量即可
- 使用下列指令检查是否成功
1
cmake --version
1.4 插件安装
- C/C++:提供代码的提示、调试与浏览
- CMake:用于借助
CMakeLists.txt
文件生成Makefile
,后者可以被Make工具用于编译 - CMake Tools:用于辅助提示编写
CMakeLists.txt
文件
二、代码编译
2.1 单文件编译
- 写好一个简单的单文件程序后
1
2
3
4
5
6
#include <iostream>
int main()
{
int a = 11; int b = 22;
std::cout << "a + b = " << a + b << "\n";
}
- 我们新建一个终端,然后我们就可以在终端内使用相关Linux命令来进行代码文件的编译了
- 使用如下指令即可生成该文件的
.exe
可执行文件,注意C++和C的源文件对应的指令的区别
1
2
g++ file_name.cpp
gcc file_name.c
- 我们也可以用
-o
来指定生成的可执行文件的文件名,若不指定则默认名称为a.exe
1
2
g++ file_name.cpp -o yourname
gcc file_name.c -o yourname
- 然后我们即可运行已有的可执行文件
2.2 多文件编译
2.2.1 基于命令
- 用于测试的多文件结构如下
1
2
3
4
5
6
- include/
- Header.h
- src/
- Source1.cpp
- Source2.cpp
- Test.cpp
- 其内内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* Header.h */
#ifndef _HEADER_H_
#define _HEADER_H_
void Function1();
void Function2();
#endif
/* Source1.cpp */
#include <iostream>
void Function1()
{
std::cout << "Func1" << "\n";
}
/* Source2.cpp */
#include <iostream>
void Function2()
{
std::cout << "Func2" << "\n";
}
/* Test.cpp */
#include "Header.h"
int main()
{
Function1();
Function2();
}
- 我们通过以下命令来链接上述四个文件并生成可执行文件
Main.exe
1
g++ .\src\Source1.cpp .\src\Source2.cpp .\Test.cpp -o Main -I .\include\
- 其中
-o
用于指定可执行程序的文件名,-I
则用于指定.cpp
源文件中使用#include
包含的头文件应当在何处(注意到我们包含头文件时并没有使用相对路径)进行检索,不填则默认在文件根目录.\
进行检索
2.2.2 基于CMake
- 我们在文件根目录添加一个
CMakeLists.txt
文件,我们可以在里面写一些函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 必须放在CMakeLists.txt文件的开头,用于指定所需的CMake的最低版本,此命令只能执行一次
cmake_minimum_required(VERSION 3.10)
# 该函数必须紧随cmake_minimum_required()函数之后,用于指定项目名称、版本、描述等信息
project(ProjectName)
# 该函数第一个参数接收地址,第二个参数(可自定名称)用于搜索地址后记录该地址下的.cpp源文件
aux_source_directory(src SrcSub) # 搜索根目录下的src文件夹内的源文件
aux_source_directory(. SrcCur) # 搜索根目录下的源文件
# 该函数用于生成可执行文件,第一个参数指定文件名,往后的参数以空格间隔,传入先前导出的那几个变量
add_executable(Main ${SrcSub} ${SrcCur})
# 该函数用于指定头文件的搜索路径,可以有多个路径,此处是指在根目录下的include文件夹内进行搜索
include_directories(include)
- 然后在VSCode内按下
Ctrl + Shift + P
快捷键,如下图进行编译器的选择(别选VS的那些)
- 选择完成后就会在根目录自动生成(之后每修改该文件后进行保存时,都会重新生成)
build
文件夹,然后我们就可以依据其中Makefile
文件内的规则进行代码的Linking与可执行文件的生成
- 然后我们就可以打开终端,
cd
到build
所在的目录,然后使用指令cmake ..
(若报错无法识别指令cmake
,则卸载插件CMake和CMake Tools并重装后重启VSCode即可)
- 上述步骤都执行成功后,我们即可在命令行中使用
mingw32-make.exe
指令(该工具可在MinGW的文件夹目录下的bin
目录下找到,名字有可能有所不同),这就可以使得项目依据Makefile
文件内的规则进行编译
- 至此我们即可使用该
.exe
文件了,若我们需要对代码进行调试,则需要配置tasks.json
和launch.json
文件,若无需调试则可不管,每次直接Ctrl + F5
生成可执行文件即可
三、代码调试
若只需要一个可执行文件,则这下面的内容于你无用;但项目的开发必然伴随着无数的调试,想要在VSCode中对C++代码进行调试,除非使用CompileRun插件直接一键搞定,否则都需要手动对下面这些文件进行配置
3.1 创建tasks.json与launch.json
- 打开你的
main()
函数所在的.cpp
源文件,按Ctrl + Shift + P
打开配置面板,进行如下操作便可生成tasks.json
和launch.json
两个文件
- 此时默认生成的配置内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/* tasks.json */
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe 生成活动文件",
"command": "D:\\VSCODE\\mingw64\\bin\\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": "build",
"detail": "调试器生成的任务。"
}
],
"version": "2.0.0"
}
/* launch.json */
{
"configurations": [
{
"name": "C/C++: g++.exe 生成和调试活动文件",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "D:\\VSCODE\\mingw64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++.exe 生成活动文件"
}
],
"version": "2.0.0"
}
3.2 配置tasks.json
- 下面是一个参考模板,可见该文件需要依赖我们使用
CMakeLists.txt
生成的build
内的内容来运作以链接各头文件与源文件,最终借助launch.json
调用该文件内的一系列自动化命令生成项目的可执行文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
"version": "2.0.0",
"options": {
"cwd": "${fileDirname}/build/" //相当于一个cd命令,进入build文件的目录
},
"tasks": [
{
"label": "cmake", //标签设置为cmake
"type": "shell", //在命令行中执行指令
"command": "cmake", //(在build目录下的命令行)执行cmake指令
"args": [ //上述命令的参数列表
".." //相当于使用"cmake .."命令
],
},
{
"label": "make",
"group":{
"kind": "build",
"isDefault": true
},
"command": "mingw32-make.exe", //执行该命令生成可执行文件
"args":[ //无需参数
]
},
{
"label": "Build The Project", //将此标签指定给launch.json中的"preLaunchTask"参数,使得自动化完成程序的链接与编译
"dependsOn":[
"cmake", //执行上述"label"为"cmake"的花括号内的"command"指令
"make" //执行上述标签为"make"的"command"指令
]
}
]
}
- 上面的这个配置设计了一个总任务
Build The Project
对两个步骤的子任务(cmake
和make
)进行管理,这个总任务会在launch.json
文件中预先调用以生成可执行文件
3.3 配置launch.json
- 注意
"miDebuggerPath"
项参数要给到电脑本地的gdb.exe
路径,不然无法调试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
"version": "0.2.0",
"preLaunchTask": "Build The Project", //对应tasks.json文件中标签为"Build The Project"的任务,即先完成tasks.json中的对应工作内容,再完成launch.json的工作内容
"configurations": [
{
"name": "(gdb) 启动",
"type": "cppdbg", //正在使用的调试器,使用Visual Studio Windows时必须为cppvsdbg;使用GDB或LLDB时必须为cppdbg
"request": "launch", //表示此配置是用于启动程序还是附加到已运行的实例上
// "program": "输入程序名称,例如 ${workspaceFolder}/a.exe", //要执行的可执行文件的完整路径
"program": "${workspaceFolder}/build/Main.exe", //CMake系列方法生成的可执行文件位置,此处.exe文件名字要与CMakeLists.txt内的保持一致
"args": [],
"stopAtEntry": false,
// "cwd": "${fileDirname}", //设置调试器启动的应用程序的工作目录
"cwd": "${workspaceFolder}/build", //CMake生成的可执行文件目录
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "D:\\VSCODE\\mingw64\\bin\\gdb.exe", //指定gdb调试器位置
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}
- 此时我们就可以在VSCode的侧边栏的按钮进行调试
- 此时不能直接对源文件使用右上角按钮进行运行(CompileRun也不行),大概率会出问题
- 若
#include
未使用相对路径,就会导致报错,因为使用CMakeLists.txt
时的头文件包含是可以不写路径而直接写头文件名字的 - 此时的
tasks.json
内执行的是CMake相关指令,所以直接运行源文件的话可能导致无法链接所有源文件的情况(即只会编译被运行的源文件内的内容,而其它没被包含进来的代码都不会被Linking进来,这就会导致一些空实现的问题)
- 若
3.4 关于插件CompileRun的使用
- 使用插件
C/C++ Compile Run
提供的如下的第一个按钮即可一键运行单文件代码(多文件可能会产生问题),使用第二个按钮即可进行调试而无需配置tasks.json
和launch.json
文件 - 这种方式产生的运行时缓存文件会存放在被编译源代码目录下的
output
文件夹中,注意要添加到忽略列表中进行忽略
- 但是该插件只会编译被运行的单个源文件的内容,而其它没被包含进来的源代码都不会被Link进来(也可能是我不会设置),这就可能会导致一些空实现的问题,所以要注意以下几点
#include
的头文件应当同时包含声明与实现,若仅在.h
内写了声明,在某个.cpp
内写了实现,该插件在运行包含了该.h
声明的源代码时就会导致无法链接到.cpp
实现的错误#include
的头文件应当使用相对路径而不仅仅是头文件名,否则会报错
本文由作者按照 CC BY-NC-SA 4.0 进行授权