前言
目前工作和学习中我基本都使用 vscode 作为主要开发工具,所以有必要记录一下我的常用 vscode 配置,不用每次换完机器都重新找各种教程配置一遍,这一篇主要是 vscode 本身相关的一些关于 c++ 项目的基本配置,包括代码补全、单文件项目和多文件项目的编译、调试和运行等,后面可能还会总结一下常用代码检查器、还有 ROS 相关的配置等。
前提条件
- 系统需要安装 c++ 编译器等相关工具以及gdb,可以通过以下命令安装
sudo apt install build-essential gdb
- vscode 需要安装
C/C++
插件
下面主要分成三部分介绍,分别是代码补全、项目编译运行、以及调试,分别对应三个对应的配置文件。为了方便演示,我以下面一个代码文件结构进行演示:
FileCopier
├── bin---------------------------编译之后的二进制文件
│ └── ...
├── data--------------------------数据文件
│ ├── input_text.txt
│ └── output_text.txt
├── include-----------------------头文件
│ └── FileCopier.hpp
├── src---------------------------源代码
│ ├── FileCopier.cpp
│ └── main.cpp
└── .vscode-----------------------vscode 配置文件
├── c_cpp_properties.json
├── launch.json
├── settings.json
└── tasks.json
项目(主要在 FileCopier.cpp
定义)的功能是:接受两个文件路径作为输入和输出参数,按行读取输入文件,显示在 console 上并输出到输出文件中,起一个复制的作用
单源文件/简单项目设置
代码补全
首先是代码补全,通过 Ctrl + Shift + p
运行 C/C++: Edit Configuration
会自动在当前打开的文件夹下的 .vscode
中生成一个 c_cpp_properties.json
文件,如下所示:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"/usr/local/include/**",
"${workspaceFolder}/include/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++14",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
基本的模板会和上面有点区别,这里我主要修改了几个参数:
compilerPath
这个如果在 ubuntu 通过build-essential
安装了 gcc 的话基本不用修改默认路径cStandard
和cppStandard
规定代码中使用的 c/c++ 标准intelliSenseMode
这一项是智能补全的模型,这里我没改变includePath
这一项是比较关键的头文件的 include 路径,这里我根据我当前项目结构改成了:"/usr/local/include/**"
:常用标准库的路径"${workspaceFolder}/include/**"
:当前项目的头文件的 include 路径- 注意路径中如果用
*
意味着不会递归搜索,即只会搜索该文件夹下的文件而不会搜索其子文件夹中的文件,**
表示递归搜索
项目编译及运行
编译
vscode 中的项目编译和运行(以及其他 shell 脚本的运行)可以以 tasks 的形式配置,通过 vscode 窗口中,Terminal -> configuration tasks
选择 C/C++: g++ build active file
会自动在当前打开的文件夹下的 .vscode
中生成一个 tasks.json
文件,如下所示:
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "C/C++: g++ build active project",
"command": "/usr/bin/g++",
"args": [
"-I",
"${workspaceFolder}/include",
"-g",
"${workspaceFolder}/src/*.cpp",
"-o",
"${workspaceFolder}/bin/${workspaceFolderBasename}"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
"group": "build"
}
]
}
同样,基本的模板会和上面有点区别,这里我主要是根据项目结构修改了几个参数:
label
: task 的名称,在之后会用到command
: 相当于输入我们想通过 task 运行的指令,指令的类型通过type
限定,这里我们用 g++ 进行 c++ 项目的编译args
:针对上面用到的command
给定的参数,这里就是g++
的参数,作为项目的话,通常头文件和输出二进制文件可能会不在一个文件夹里,所以我按照我的文件路径来设置,分别是:-I
:指定 include 路径,这里是项目文件夹/include
-g
:源文件路径,项目文件夹/src/所有cpp文件
-o
:编译好的二进制路径,这里是项目文件夹/bin/项目文件夹名称
设置好,按 Ctrl + Shift + b
,选择上面 task 的label 即可编译,termial 输出结果是:
> Executing task: /usr/bin/g++ -I /workspaces/my_docker_projects/FileCopier/include -g /workspaces/my_docker_projects/FileCopier/src/*.cpp -o /workspaces/my_docker_projects/FileCopier/bin/FileCopier <
Terminal will be reused by tasks, press any key to close it
查看 bin 文件夹:
root:/workspaces/my_docker_projects/FileCopier# ls bin/
FileCopier
可以看到已经成功编译生成了相应的二进制文件
运行
同样,运行项目实际上也是一条 shell 指令,我们可以创建 task 来配置,这里创建如下:
{
"version": "2.0.0",
"tasks": [
{
"label": "C/C++: g++ build active project",
//...
},
{
"type": "shell",
"label": "C/C++: run active project",
"command": "bin/${workspaceFolderBasename}",
"args": [
"${workspaceFolder}/data/input_text.txt",
"${workspaceFolder}/data/output_text.txt"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
"group": "build"
}
]
}
跟编译类似,command
中设为对应的 shell 指令,这里是二进制文件路径,arg
则输入项目对应的参数,这里是输入文件路径和输出文件路径,运行方式同样 Ctrl + Shift + b
:选择对应label
,这里应该是 C/C++: run active project
,输出结果如下:
> Executing task: bin/FileCopier /workspaces/my_docker_projects/FileCopier/data/input_text.txt /workspaces/my_docker_projects/FileCopier/data/output_text.txt <
Hello World!
File copied!
Terminal will be reused by tasks, press any key to close it.
上面 Hello World
是输入文本文件里的内容,File copied
是程序中输出表示复制完成,比较一下两个文件:
root:/workspaces/my_docker_projects/FileCopier# diff data/input_text.txt data/output_text.txt
root:/workspaces/my_docker_projects/FileCopier#
输出无区别,表示程序正确运行。
编译和运行
目前我们已经通过两个 task 分别实现了编译和运行。有没有办法同时执行编译和运行呢?答案是同样可以通过 task 来实现,我们创建以下 task:
{
"version": "2.0.0",
"tasks": [
{
"label": "C/C++: g++ build active project",
//...
},
{
"label": "C/C++: run active project",
//...
},
{
"type": "shell",
"label": "C/C++: g++ build & run active project",
"command": "echo",
"args": [
"Project built and run!"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
],
"dependsOn": [
"C/C++: g++ build active project",
"C/C++: run active project"
],
"group": "build"
}
]
}
以上 task 大部分和之前两个没什么区别,唯一在于 dependsOn
这个参数制定了在 task 执行 command
需要依赖于什么 tasks, 这里我们放入前两个 task 的label。因此执行这个 task 就可以相当于同时执行编译+运行了,由于两个 tasks 会用两个 terminal,运行结果如下:
# 在 1.C++: g++ build & run active project terminal 中
# 第一个 task 运行
> Executing task: /usr/bin/g++ -I /workspaces/my_docker_projects/FileCopier/include -g /workspaces/my_docker_projects/FileCopier/src/*.cpp -o /workspaces/my_docker_projects/FileCopier/bin/FileCopier <
Terminal will be reused by tasks, press any key to close it.
# 第三个 task 运行
> Executing task: echo 'Project built and run!' <
Project built and run!
Terminal will be reused by tasks, press any key to close it.
# 在 2.C++:Task- C/C++: run active project terminal 中
# 第二个 task 运行
> Executing task: bin/FileCopier /workspaces/my_docker_projects/FileCopier/data/input_text.txt /workspaces/my_docker_projects/FileCopier/data/output_text.txt <
Hello World!
File copied!
Terminal will be reused by tasks, press any key to close it.
针对简单单文件的设置
有些情况下,我们实际上并不需要针对一个项目编译(没有头文件,源代码也只有一份,C语言课程作业或者leetcode解答等情况..)这个时候实际上用生成的默认 tasks.json 的模板即可,大致如下:
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "g++ build active file",
"command": "/usr/bin/g++",
"args": ["-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}"],
"options": {
"cwd": "/usr/bin"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
其余的运行以及编译 + 运行的task可以参考上面的部分,但是要注意的是,如果是针对 active file
的编译(如上 task 有 ${file}
等等),记得一定要在打开你想编译源文件下执行对应的 task !否则会显示错误文件类型之类的错误,这一点和上面我的设置是不一样的,如果是参考我以上三个task的设置的话,可以注意到中间没有用到涉及 filename
的变量,所以不需要打开对应源文件,甚至不打开任何文件都可以,但是要注意我使用了 ${workspaceFolder}
,所以需要 vscode 中打开的文件夹是我们的项目文件夹的根目录。
GDB 调试
首先需要确保电脑中已经安装了 gdb,然后通过 vscode 窗口中 Run -> add configuration
。会自动在当前打开的文件夹下的 .vscode
中生成一个 launch.json
文件,如下所示:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "g++ - Build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/${workspaceFolderBasename}",
"args": [
"${workspaceFolder}/data/input_text.txt",
"${workspaceFolder}/data/output_text.txt"
],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++ build active project",
"miDebuggerPath": "/usr/bin/gdb"
}
]
}
这里我基本没有做太多的修改(对 gdb 还不是很熟悉哈哈)。主要看的参数有以下几个:
"program"
:要调试的二进制文件路径"args"
:项目输入参数"stopAtEntry"
:要不要在开始进行调试时暂停"preLaunchTask"
:在进行调试之前需要进行的 task,(通常是编译项目),这里我设为之前创建的编译 task。
然后按 F5
或者侧边栏中 Run
都可以进入调试,调试界面如下:
左侧 variable
可以观察当前局部变量和全局变量,watch
设定观测点,call stack
查看程序调用栈。添加断点的方法是是行号左侧单击一下,右键编辑断点可以增加条件,其他单步运行等操作在上方。
结语
目前为止,这篇笔记总结了 vscode 中配置简单 c++ 项目的编译和调试相关开发环境。本来还想总结下多文件(相对大型)项目的编译,时间有限只能放在下一篇了。有什么意见或者建议欢迎交流!