0%

使用VScode编写C++工程

VS code 是个功能强大,可扩展性极强的编辑器,通过添加一些插件,修改一下配置即可发挥强大的功能。

前些日子(其实好久了哈 ( ̄ y▽  ̄)~*),通过阅读官网的文档,成功 配置了C++的编程环境,然后用了很久。但是最近遇见了个很严重的问题,那就是按照官网的文档走的话,最终只能编译,调试,运行一个单独的文件。

这就很难受了,虽说刷刷算法题也不需要多个文件,使用 g++的一些较为复杂的参数也可以编译链接多个文件,但是,到底能不能使用 VS code 来编写具有一定规模的 C/C++工程呢?

于是,折腾开始了,而且最终取得了很不错的成果。(≖‿≖)✧

折腾之前

因为之前的配置,所以计算机上至少有的环境是:安装好了 MingW,设置过了全局,安装了官网文档中所需要的插件以及写好了配置。

要是这一步没有做过的话可以参考我之前的文章 使用VS从哦的编写C++文件,或者阅读官方文档

准备好了,开始! o(*≧▽≦)ツ

安装 C/C++ Project Generator

在最早配置 C++编程环境的时候,就有过这个插件的印象,只是没实际使用过,不过,看名字貌似是我们想要的插件,emmmm,那就安装!

按照文档的提示:

How to use

  1. Go to command pallete (usually : ctrl + shift + p)
  2. Search for “Create C project” or “Create c++ project” depending on your preference
  3. Select the folder where the project should be created
  4. That’s it, project will open
  1. 使用ctrl + shift + p 调出命令界面。
  2. 根据需要输入 Create C project 或者 Create c++ project 查找相关命令选择建立 C 工程或者 C++工程(本次折腾用的是 C++工程)
  3. 选择希望在哪里建立工程
  4. 到这里就结束了,工程建立完毕

嗯,那根据它的说法来一次。

可以看到已经有了一个工程的雏形,插件也很贴心的给了示例程序。

那好,然后按下F5开始调试。

∑(っ °Д°;)っ开始运行了!竟然如此简单!

完结撒花( ^3^ )╱~~❀❀❀

才怪(/= _ =)/~┴┴

launch.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
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/main.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"preLaunchTask": "build",
"linux": {
"MIMode": "gdb"
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb"
}
}
]
}

emmmm 还是能简单看懂一些的了,大致是在官方的模板下少许修改了一下,甚至贴心的为不同的环境选择了不同的调试器,那么,问题出在哪里呢?

贴一下之前按照官方给的配置文件模板。

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
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"miDebuggerPath": "C:\\mingw\\bin\\gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build hello world"
}
]
}

稍加思索

显然,该配置文件没有配置调试器的路径,于是加上配置"miDebuggerPath",一通魔改融合后,修改完的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
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/main.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"miDebuggerPath": "C:\\MinGW\\mingw64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build"
}
]
}

= ̄ ω  ̄= 因为我还只是在 Windows 上配置环境,没考虑跨平台,于是就只保留了 Windows 上的配置。

miDebuggerPathpreLaunchTask的值因人而异吧,我是改了一堆,但实际上只需要加上miDebuggerPath就行了。

那,再试试?

喜极而泣(´°̥̥̥̥̥̥̥̥ω°̥̥̥̥̥̥̥̥ `)

开开心心设断点,开开心心 debug(`・ω・´)

喵~?

我的断点呢?

它怎么灰了 ಠ౪ಠ?

它怎么没停下来 ಥ_ಥ?

怎么变量没自己打开 (╯‵□′)╯︵┻━┻?

我去,还是无效值(╬▔ 皿 ▔)!

(/“≡ _ ≡)/~┴┴

g++ -g

鬼知道我查了多久资料( _ _)ノ|

来大致谈谈这个插件的一些细节。

作者的思路蛮正确的,基本上还是官方给的配置,然后魔改了一下,比如说task里需要放很多的任务,其中有一个叫做“build”,在官网的模板中,这个任务是要调用命令行里的g++命令来编译程序,但是指定了编译时的源文件与生成文件,这就导致写代码的时候文件名不能出错。

但实际上在一个工程中,需要编译的文件可能是多个,所依赖的头文件也会是多个,这些在生成可执行程序的时候都是需要考虑到的,诚然,可以通过 g++丰富的参数写下长长的命令来实现编译链接多个源文件,可是毕竟麻烦,而且还容易出错。

于是作者使用了 Makefile 这个工具。Makefile 是一个比较有意思的工具,简单的说,它可以通过检查一些依赖项,然后调用一些命令加上相应的参数生成所需要的文件。

用在编译程序上可谓是刚刚好。

所以在作者的修改下,task 文件中的任务被描述为调用 Makefile 的一些命令,而 Makefile 里又进行了相应的配置,将依赖项分别放入_src_,_lib_,_include_中,调用_g++_命令编译文件。

Makefile 里最重要的几句无疑就是最后这个了:

1
2
$(BIN)/$(EXECUTABLE): $(SRC)/*
$(CC) $(C_FLAGS) -I$(INCLUDE) -L$(LIB) $^ -o $@ $(LIBRARIES)

这句中的 CC 是命令g++,后面相关的参数有-I-L-o等,这些参数的详细说明我就不介绍了,贴出来我查找到的一些资料:

g++命令参数的作用即用法

那么问题出现在哪里呢?

再列出我参考的一些资料:

C/C++ Project Generator 的反馈中,国外某位程序员的回答

StackOverFlow 上,关于 VS code 无法调试的回答

以及官网给出的task模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello world",
"type": "shell",
"command": "g++",
"args": ["-g", "helloworld.cpp"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

虽然一下子列出来资料会得出显而易见的结论,但鬼知道为了找到这些资料有多辛苦(╯-_-)╯╧╧

总的来说,就是原作者在写_Makefile_的时候,漏掉了一个参数-g,导致无法调试,那么所需要进行的修改就是给它加上。

修改后的 Makefile 最后几句如下:

1
2
$(BIN)/$(EXECUTABLE): $(SRC)/*
$(CC) $(C_FLAGS) -I$(INCLUDE) -L$(LIB) -g $^ -o $@ $(LIBRARIES)

调试,启动(*゚ ▽ ゚*)

开开心心 Debug。(^ ∀ ^)

完整的配置

贴出魔改之后我的配置文件吧:

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
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/main.exe",
"args": ["<", "bin\\data.in", ">", "bin\\data.out"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:\\MinGW\\mingw64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build main"
}
]
}

task.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"version": "2.0.0",
"tasks": [
{
"label": "build main",
"type": "shell",
"command": "powershell",
"args": ["-c", "mingw32-make"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

Makefile

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
CC      := g++
C_FLAGS := -std=c++17 -Wall -Wextra

BIN := bin
SRC := src
INCLUDE := include
LIB := lib

LIBRARIES :=

ifeq ($(OS),Windows_NT)
EXECUTABLE := main.exe
else
EXECUTABLE := main
endif

all: $(BIN)/$(EXECUTABLE)

clean:
$(RM) $(BIN)/$(EXECUTABLE)

run: all
./$(BIN)/$(EXECUTABLE)

$(BIN)/$(EXECUTABLE): $(SRC)/*
$(CC) $(C_FLAGS) -I$(INCLUDE) -L$(LIB) -g $^ -o $@ $(LIBRARIES)

写在最后

折腾了一天后,有了个较为完善的解决方案,很可惜的是,没有找到可以完美创建,调试 C++工程的插件,但是可以根据已有的思路一步步完善自己的配置。

我的想法是,将已经配置好的 vscode 工程文件存为模板文件,需要的时候拷贝一份使用,于是,原插件也用不上了。

其实原来的插件稍加修改一下也可以完美胜任的,但是原作者貌似已经好久不更新了,无论是在 VS code 的插件库,还是原作者的 GitHub 库,都已经有人进行了一系列反映,甚至给出了解决方案,但是貌似作者并没有看到哈。博主又比较笨,不会修改原作者的代码,那就先这样用吧。

有一点比较在意的是,在很多 IDE 中,如果创建的是终端工程的话,会在程序运行结束后停留在结束界面。这点除了在代码最后调用系统命令pause外,没有什么好的办法。

但毕竟 C++不是只用来写终端程序的,这一点倒也不是很严重。

那就这样吧。(/・ω・\)