# VS Code调试C/C++程序
[toc]
记录用VS Code调试C/C++程序的基本流程,加深对工程构建、编译链接的理解。我自己目前的体会是不适合在实际工程中使用,除非对makefile工程构建、C/C++相关的工具链有深刻的认识,否则很难驾驭。
## 搭建VS Code C/C++调试环境
按照《参考1》搭建VS Code C/C++调试环境,大致的流程如下,
1. 安装VS CODE
VSCODE是微软免费的跨平台的开发平台框架,从其官网下载安装即可;
2. 安装微软的C/C++插件
* 打开VS Code.
* 单击左侧工具栏的扩展图标
* 搜索c++.
* 点击安装, 软后重启VSCODE.
![微软的C/C++插件图片](https://box.kancloud.cn/ed4166c41ff3ebda288c53f6e446f180_675x156.png)
插件安装以后,打开一个包含C/C++源码的文件夹时,VSCODE会自动添加一个包含设置文件的子目录.vscode
> 注意,微软的C/C++插件并不包含C++编译器和调试器,这些需要自己安装,比较常用的C++编译器有Windows下的mingw-w64、macOS下的Clang for XCode和linux下的GCC,Windows需要把工具链的安装地址添加至环境变量PATH里。
3. 配置IntelliSense
打开相关文件夹后,微软的C/C++插件会根据系统的编译器尝试提供基本的配置,如果没有成功配置,就需要自己生成一个配置文件c_cpp_properties.json,方法如下:
* 打开命令面板(Ctrl+Shift+P或菜单[查看]->[命令面板])
* 运行命令C/Cpp: Edit configurations...
* 生成c_cpp_properties.json,该配置文件保存于.vscode文件夹下
以下是基于Windows下MinGW C++编译器生成的默认配置文件c_cpp_properties.json.
```
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "",
"compilerPath": "C:\\MinGW\\bin\\gcc.exe",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
```
4. Build代码
如果你想build代码,你需要配置task.json文件:
* 打开命令面板(Ctrl+Shift+P或菜单[查看]->[命令面板])
* 选择命令Tasks: Configure Tasks...,单击创建文件tasks.json,你会看到一系列任务运行模板
* 选择模板Others :运行任意外部命令的示例
* 修改command命令行表达式,以build代码,如g++
* 添加需要的args(如-g用来调试)
* 修改label,使其有描述性
tasks.json示例代码,如下:
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello world",
"type": "shell",
"command": "g++",
"args": [
"-g", "helloworld.cpp"
]
}
]
}
```
如果你想通过菜单[任务]->[运行生成任务...]或快捷键(Ctrl+shift+B)build代码,需要在刚才的文件tasks.json添加组build,如下,这样就可以build代码生成可执行的文件了:
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello world",
"type": "shell",
"command": "g++",
"args": [
"-g", "helloworld.cpp"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
```
5. 调试代码
调试,需要生成文件launch.json:
* 点击左侧工具栏的调试图标
* 在Debug视图,点击Configure图标
* 选择C++ (GDB/LLDB),生成文件launch.json,有两个配置项
* C++ Launch 定义当你启动调试加载你的应用时的属性
* C++ Attach 定义已经运行进程的附加属性
* 更新program属性,添加自己的调试目录
* 如果你想在调试之前build自己的代码,需要添加preLaunchTask属性,该属性的内容为刚才在task.json中创建的任务的label(如之前的 "build hello world")
以下是用MinGW GDB调试器的launch.json配置文件的内容:
```
{
"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"
}
]
}
```
至此,点击左侧工具栏的调试图标,再点击绿色的运行图标,就能build代码->调试程序了,这时,在终端已经可以看到“hello world”了!
## 一个简单的C/C++程序调试
没有实践的理论就是空中楼阁。
1. 新建并打开一个源码文件结构
* 新建一个目录ex
* 目录下新建文件hello.cpp,如下:
```
#include <stdio.h>
int main(int argc, char const *argv[])
{
printf("hello world!\n");
printf("hello world!\n");
getchar();
return 0;
}
```
* 打开VSCODE,[File]->[Open Folder]打开文件夹
2. 配置IntelliSense
打开命令面板(Ctrl+Shift+P或菜单[查看]->[命令面板]),运行命令C/Cpp: Edit configurations...,生成c_cpp_properties.json,该配置文件保存于.vscode文件夹下,以下是基于linux下GCC编译器生成的默认配置文件c_cpp_properties.json:
```
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/clang++-3.5",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
```
> 需要关注的有两项,"includePath"为包含文件的目录,根据源码结构自行设置,由于该源码就一个hello.cpp文件,不用设置,默认的即可;"compilerPath"为编译器的目录,根据需要修改
3. Build代码
* 新建build任务,这个任务的作用是提供编译链接的脚本,个人理解,执行这个任务后会在本地目录生成目标文件
* 菜单[Tasks]->[Run Build Task...],此时会提示没有找到Build任务,是否需要去配置Build任务,只能跟着去做任务了,创建一个以Others为模板的Build任务配置文件tasks.json如下,
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build hello", // 起个自己喜欢的名字
"type": "shell",
"command": "g++", // 编译的命令
"args": [ // 编译命令的参数,会不会下就看会不会这些编译命令的使用了
"-g", "ex.cpp", "-o", "qb.out"
],
// 以上是以Others为模板的Build任务配置文件tasks.json的内容
// 菜单[Tasks]->[Run Build Task...],还是提示在build hello工程里没有build任务,按提示配置即生成如下配置内容
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
```
* 菜单[Tasks]->[Run Build Task...],执行以上配置的编译链接的任务,其实就是执行了一条编译命令
> g++ -g ex.cpp -o qb.out
这时可以在目录下发现生成的目标文件qb.out
4. 调试代码
* 点击左侧工具栏的调试图标->Configure图标->选择C++ (GDB/LLDB),生成文件launch.json,
```
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/qb.out", // 输出文件
"args": [],
"stopAtEntry": false, // 开始调试时,是否停在程序入口
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb", // 调试命令
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
// 以下是另添加,作用是调试前的的任务,下面定义的是之前定义的那个build任务
"preLaunchTask": "build hello"
}
]
}
```
* 点击绿色的运行图标即可调试,OK!
## Makefile构建的C/C++程序调试
VS Code 配合 Makefile 来提高 C/C++ 工程的可移植性,这个方案的思路是:使用 Makefile 来构建工程, VS Code 通过 Tasks 调用 make 工具来编译,通过调用 gdb 来调试。其优点在于不是过分依赖 VS Code 自身的配置,一个合适的 Makefile 可以在各个平台上执行编译,但是在开发过程中又可以用到 VS Code 自身的插件带来的便利,减少命令输入,减少命令行 gdb 调试带来的烦恼。
* **准备工作**
准备一套 Makefile 模板,比如说 https://github.com/TheNetAdmin/Makefile-Templates ,或者也可以自行写一套模板,一个好的 Makefile 模板可以省去很多麻烦;
安装编译工具与 make 工具:尤其是在 Windows 下,使用 make 是一个比较麻烦的事情,推荐大家使用 msys 提供的一套工具,这里有一个打包供下载 https://pan.baidu.com/s/1kV5hx3p
1. 首先构建一个 Makefile ,如果没有合适的可以到这里找到一些现成模板
这里的makefile文件,如下:
```
# originating https://github.com/TheNetAdmin/Makefile-Templates
# tool marcros
CC := g++
CCFLAG := -std=c++14
DBGFLAG := -g
CCOBJFLAG := $(CCFLAG) -c
# path marcros
BIN_PATH := bin
OBJ_PATH := obj
SRC_PATH := src
DBG_PATH := debug
# compile marcros
TARGET_NAME := main
ifeq ($(OS),Windows_NT)
TARGET_NAME := $(addsuffix .exe,$(TARGET_NAME))
endif
TARGET := $(BIN_PATH)/$(TARGET_NAME)
TARGET_DEBUG := $(DBG_PATH)/$(TARGET_NAME)
MAIN_SRC := src/main.cpp
# src files & obj files
SRC := $(foreach x, $(SRC_PATH), $(wildcard $(addprefix $(x)/*,.c*)))
OBJ := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
OBJ_DEBUG := $(addprefix $(DBG_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
# clean files list
DISTCLEAN_LIST := $(OBJ) \
$(OBJ_DEBUG)
CLEAN_LIST := $(TARGET) \
$(TARGET_DEBUG) \
$(DISTCLEAN_LIST)
# default rule
default: all
# non-phony targets
$(TARGET): $(OBJ)
$(CC) $(CCFLAG) -o $@ $?
$(OBJ_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAG) -o $@ $<
$(DBG_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAG) $(DBGFLAG) -o $@ $<
$(TARGET_DEBUG): $(OBJ_DEBUG)
$(CC) $(CCFLAG) $(DBGFLAG) $? -o $@
# phony rules
.PHONY: all
all: $(TARGET)
.PHONY: debug
debug: $(TARGET_DEBUG)
.PHONY: clean
clean:
@echo CLEAN $(CLEAN_LIST)
@rm -f $(CLEAN_LIST)
.PHONY: distclean
distclean:
@echo CLEAN $(CLEAN_LIST)
@rm -f $(DISTCLEAN_LIST)
```
2. 根据这个 Makefile,构建一个目录结构如下的工程目录
```
- Project
- Makefile
- src: 所有源文件 (不得放在子目录)
- add.cpp
- add.h
- sub.cpp
- sub.h
- main.cpp
- obj
- 空
- debug
- 空
- bin
- 空
```
4. 然后对于 VS Code 的 tasks.json 和 launch.json 做一些修改
文件tasks.json
```
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "make",
"args": [
"default"
],
"type": "shell"
},
{
"label": "build-debug",
"command": "make",
"args": [
"debug"
],
"type": "shell"
},
{
"label": "clean",
"command": "make",
"args": [
"clean"
],
"type": "shell"
}
]
}
```
文件launch.json
```
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
// 修改为新的测试目标文件路径
"program": "${workspaceRoot}/debug/main",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
//"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build-debug"
}
]
}
```
到此可以按上节的步骤使用编译和调试工具了。
## STM32嵌入式程序调试
参考[使用VSCode和VS2017编译调试STM32程序](https://www.cnblogs.com/WeyneChen/p/8379214.html),能下载运行,不能正常调试。
![JLINK出错图片](https://box.kancloud.cn/719f6dbcc283d4db77e1e9f7b81c0707_576x582.png)
也许是JLINK不是正版造成的,也许是哪没设置正确,以后再整。
## 参考资料
* 参考1:[C/C++ for VS Code (Preview)之官方文档](https://code.visualstudio.com/docs/languages/cpp)
* 参考2:[VS Code 配置 C/C++ 环境](https://blog.csdn.net/wzxlovesy/article/details/76708151)
* 参考3:[使用VSCode和VS2017编译调试STM32程序](https://www.cnblogs.com/WeyneChen/p/8379214.html)