VScode 配置更优体验的C++环境
本教程适合对Visual Studio不太熟悉,同时又是VScode的重度患者,喜欢DIY环境的同学。
一、基础插件
以下插件的安装和配置可以参考如下视频链接
参考视频:
插件安装教程
clangd插件参数配置教程
下面是选择这些插件的原因,以及这些插件有哪些优势,感兴趣的同学可以看一下,跳过影响也不大。
1.1 编译器的选择(clang/clang++)
- 这里我选用的是
clang++
,一般C语言用clang
, C++用clang++
。 - 关于
msvc, clang, gcc
这几个编译器的优缺点,我从chatGPT搬过来一些结论放在下面,感兴趣的同学自己查看,不是本文档的重点。
-
msvc编译器是Microsoft Visual C++的缩写,它是Microsoft Visual Studio集成开发环境的一部分,可以用来编译C和C++语言编写的程序,主要用于开发Windows平台的应用。
-
msvc编译器的优点是与Windows操作系统和Visual Studio IDE的集成度高,支持Windows API和.NET Framework等微软技术,提供了丰富的调试和诊断工具,以及一些微软独有的语言扩展。
-
msvc编译器的缺点是对C语言标准的支持不完全,对C++标准的支持也比gcc和clang稍落后,对一些开源库和跨平台框架的兼容性不够好,以及使用GPL许可证的问题。
-
clang和clang++是LLVM项目的一部分,它们是基于LLVM的编译前端,可以用来编译C,C++,Objective-C等语言。gcc和g++是GNU编译器套装的一部分,它们是基于GCC的编译前端,可以用来编译C,C++,Java,Ada,Fortran,Go等语言。
-
clang和clang++的优点是速度快,内存占用小,诊断信息可读性强,兼容性好,支持静态分析,使用BSD许可证。gcc和g++的优点是支持更多的语言和平台,更流行,更稳定,使用GPL许可证。
-
clang和clang++的缺点是对C++11/14/17的支持不完全,对一些特殊的平台和指令集的支持不够好,对一些GCC扩展的支持不完善。gcc和g++的缺点是速度慢,内存占用大,诊断信息可读性差,兼容性差,不支持静态分析。
-
一般来说,clang和clang++适合用于开发环境,因为它们可以提供更快的编译速度和更好的错误提示。gcc和g++适合用于生产环境,因为它们可以提供更高的兼容性和稳定性。
一般来说,msvc编译器适合用于开发面向Windows平台的应用,特别是使用微软技术的应用。如果需要开发跨平台或遵循标准的应用,可以考虑使用gcc或clang等其他编译器。
1.2 代码提示插件(clangd)
clangd插件是一个基于clangd的C/C++语言服务器后端,它可以为VScode提供智能的代码补全、跳转定义、重命名符号、自动导入头文件、诊断错误等功能。clangd插件的优点是性能高,兼容性好,支持C++标准和静态分析。
1.3 调试器插件(codeLLDB)
codeLLDB插件是一个基于LLDB的C/C++调试器,它可以为VScode提供强大的调试功能,例如设置断点、查看变量、执行表达式、修改内存等。codeLLDB插件支持多种平台和架构,支持Rust和Swift语言,支持数据可视化和反汇编。
二、参数设置相关说明
2.1 json
文件格式介绍
json
文件和Python中的字典差不多,详细内容可以参考这篇文章
参考文章:Json文件格式介绍
2.2 VScode的路径参数说明
在vscode中定义了一些变量,在配置任务脚本时,可能会用到。本文以tasks.json脚本为例,介绍各个变量的含义。
假设当前workspace的路径为:/home/Coding/Test,workspace文件夹下的结构如下(+表示下一层):
/home/Coding/Test
+.vscode
++tasks.json
++launch.json
+main.cpp
${workspaceFolder} :表示当前workspace文件夹路径,也即/home/Coding/Test
${workspaceRootFolderName}:表示workspace的文件夹名,也即Test
${file}:文件自身的绝对路径,也即/home/Coding/Test/.vscode/tasks.json
${relativeFile}:文件在workspace中的路径,也即.vscode/tasks.json
${fileBasenameNoExtension}:当前文件的文件名,不带后缀,也即tasks
${fileBasename}:当前文件的文件名,tasks.json
${fileDirname}:文件所在的文件夹路径,也即/home/Coding/Test/.vscode
${fileExtname}:当前文件的后缀,也即.json
${lineNumber}:当前文件光标所在的行号
${env:PATH}:系统中的环境变量
2.3 launch.json
文件配置
自定义调试路径就直接修改program
参数对应的值。
注意⚠️:tasks.json
的可执行文件输出路径要与launch.json
的调试路径保持一致。
{
"version": "0.2.0",
"configurations": [
{
"name": "clang++ build and debug active file",
"type": "lldb",
"request": "launch",
// program的值是可执行文件路径,这里要和 tasks.json 中 -o 对应的可执行文件输出路径一致
// 我设置的路径必须在将C++程序编译的二进制文件放在build文件夹下才能成功调试
"program": "${fileDirname}/build/${fileBasenameNoExtension}",
// 调试过程的添加命令行参数,就是想main函数传递的参数
"args": [],
"cwd": "${workspaceFolder}",
// 前置任务,执行调试前,会先执行preLaunchTask,将这个任务定义在tasks.json文件中
"preLaunchTask": "clang++ build active file",
//调试时自动跳到调试控制台
"internalConsoleOptions": "openOnSessionStart",
//内嵌终端
"console": "internalConsole",
}
]
}
2.4 tasks.json
文件配置
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
// 与launch.json中的preLaunchTask的值相同
"label": "clang++ build active file",
// 指定编译器为clang++
"command": "clang++",
// 指定编译指令
"args": [
"-std=c++20", // 采用C++20标准
"-g", // 输出文件可以参与调试
"-Wall", // 显示所有警告
"-o", // 输出
// 输出文件路径
// Windows系统将${fileBasenameNoExtension}改为${fileBasenameNoExtension}.exe
// 同时修改lauch.json的program对应的值
"${fileDirname}/build/${fileBasenameNoExtension}",
// 输入的源文件
"${file}"
],
"group": {
"kind": "build",
"isDefault": true
},
}
]
}
2.5 相关问题说明
直接运行C++源文件不能在build文件夹中生成可执行文件的问题
按照上述配置,每次在VScode中建立一个C++项目时,需要在源文件同级目录下新建一个build文件夹保存输出的可执行程序,如果直接运行程序并没有在build文件夹中生成输出的可执行程序,需要修改Code Runer
插件的配置。
windows快捷键ctrl+shift+p
,macos快捷键cmd+shift+p
打开命令面板,输入设置,找到首选项:打开用户设置(JSON)。
在打开的文件中查找"cpp"
,将这一行的参数路径进行修改,添加上build文件夹路径,或者你直接讲这一行注释后换成如下配置:
"cpp": "cd $dir && clang++ -std=c++17 $fileName -o build/$fileNameWithoutExt && $dirbuild/$fileNameWithoutExt",
注意⚠️: Windows用户需要将上述命令中的两个$fileNameWithoutExt改为$fileNameWithoutExt.exe
简要说明这一行的含义:
cd $dir
:进入源文件所在的文件夹&&
: 接着执行下一行命令clang++ -std=c++17 $fileName -o build/$fileNameWithoutExt
: 使用clang++编译器,采用c++17标准,将源文件 $fileName 编译的可执行文件输出到build文件夹中,输出文件名为 $fileName 文件去掉后缀名的结果。
三、LLDB调试指令简介
进入调试后,可以在调试控制台输入LLDB指令查看变量或者运行表达式,下面总结了一些常用的LLDB指令。
lldb是一个开源的调试工具,它可以用来调试C/C++/Objective-C/Swift等语言编写的程序。它可以让您逐行或逐指令地执行程序,查看和修改变量、寄存器、内存等信息,设置断点、条件、观察点等,还可以使用Python脚本来扩展其功能。
lldb的调试指令有很多,这里我只列举一些常用的和重要的,你可以在终端输入输入lldb回车进入调试模式,再输入help或h命令来查看更多的指令和用法。
- run ®:启动或重启目标程序,如果有参数,可以在命令后面加上参数,例如run -v -d。
- continue ©:继续执行程序,直到遇到下一个断点或异常。
- step (s):单步执行程序,如果当前行有函数调用,会进入函数内部。
- next (n):单步执行程序,如果当前行有函数调用,不会进入函数内部。
- finish (f):从当前函数返回到上一层函数。
- stepi (si):单步执行一条汇编指令,如果当前指令有函数调用,会进入函数内部。
- nexti (ni):单步执行一条汇编指令,如果当前指令有函数调用,不会进入函数内部。
- break (b):设置断点,可以指定文件名、行号、函数名、地址等条件,例如break main.c:10或break strlen。
- breakpoint list (br l):列出所有的断点和观察点。
- breakpoint enable/disable/delete (br e/d/del):启用、禁用或删除某个或某些断点或观察点,可以指定编号或范围,例如br e 1或br d 1-3。
- breakpoint set (br s):设置断点的属性,例如条件、忽略次数、回调函数等,例如br s -c “x==10” 1或br s -i 5 2。
- watchpoint set (w s):设置观察点,可以监视某个变量或表达式的值是否发生变化,例如w s v -w write或w s -e “x+y”。
- watchpoint list (w l):列出所有的观察点。
- watchpoint enable/disable/delete (w e/d/del):启用、禁用或删除某个或某些观察点,可以指定编号或范围,例如w e 1或w d 1-3。
- print (p):打印某个变量或表达式的值,可以使用C/C++/Objective-C/Swift等语言的语法,例如p x或p *p。
- expression (expr):执行某个表达式,并打印结果,可以使用C/C++/Objective-C/Swift等语言的语法,也可以修改变量的值,例如expr x=10或expr printf(“x=%d\n”,x)。
- po:打印某个对象的描述信息,相当于expression -O --,例如po str或po [str length]。
- memory read/write (me r/w):读取或写入某个内存地址的内容,可以指定格式、大小、数量等选项,例如me r -f x -s 4 -c 16 0x1000或me w -s 1 0x1000 0xff。
- register read/write (re r/w):读取或写入某个寄存器的值,可以指定格式、大小等选项,例如re r x0或re w x0 0x1000。
- thread list (th l):列出所有的线程信息。
- thread select (th se):切换到某个线程,可以指定线程编号,例如th se 1。
- thread backtrace (th b):显示某个线程的调用栈,可以指定线程编号,例如th b 1。
- frame select (f se):切换到某个栈帧,可以指定栈帧编号,例如f se 0。
- frame variable (f v):显示某个栈帧的所有变量,可以指定变量名,例如f v x或f v *p。
- frame info (f i):显示某个栈帧的信息,例如函数名、参数、返回值等。
- image list (im l):列出所有加载的模块信息,例如名称、地址、大小等。
- image lookup (im loo):查找某个模块中的符号信息,例如函数、变量、类型等,可以指定名称、地址等条件,例如im loo -n main或im loo -a 0x1000。
- disassemble (di):反汇编某个函数或地址的指令,可以指定范围、数量等选项,例如di -n main或di -s 0x1000 -c 16。
- target create (ta c):创建一个调试目标,可以指定可执行文件的路径,例如ta c /bin/ls。
- target list (ta l):列出所有的调试目标。
- target select (ta se):切换到某个调试目标,可以指定目标编号,例如ta se 1。
- target delete (ta del):删除某个调试目标,可以指定目标编号或范围,例如ta del 1或ta del 1-3。
- target modules add (ta mo a):向某个调试目标添加模块文件,可以指定模块文件的路径,例如ta mo a /lib/libc.so.6。
- target modules list (ta mo l):列出某个调试目标的所有模块文件。
- target modules lookup (ta mo loo):在某个调试目标的模块文件中查找符号信息,可以指定名称、地址等条件,例如ta mo loo -n main或ta mo loo -a 0x1000。
- target stop-hook add (ta st a):向某个调试目标添加停止钩子,可以指定一些命令在每次停止时自动执行,例如ta st a -o “bt” -o “p x”。
- target stop-hook list (ta st l):列出某个调试目标的所有停止钩子。
- target stop-hook delete (ta st del):删除某个调试目标的停止钩子,可以指定编号或范围,例如ta st del 1或ta st del 1-3。
- target stop-hook enable/disable (ta st e/d):启用或禁用某个调试目标的停止钩子,可以指定编号或范围,例如ta st e 1或ta st d 1-3。
- settings set/show (se s/sh):设置或显示一些配置选项,例如日志级别、颜色、格式等,例如se s term-width 80或se sh prompt。
- log enable/disable/list (lo e/d/l):启用、禁用或列出日志通道和类别,可以指定日志文件和级别等选项,例如lo e gdb-remote packets或lo d gdb-remote default。
- help (h):显示帮助信息,可以指定某个命令或类别,例如h thread或h breakpoint set。
四、关于VScode更优体验的Python环境搭建
如果你也是Python爱好者,追求Python的完美编程体验,希望运行Python文件的同时又能做到实时交互查看变量,运行表达式等,可以私戳我,之后有时间再考虑写一下如何搭建更优的Python编程环境,效果图如下:
将左边的代码运行到右边的交互窗口,右边交互窗口的体验和Jupyter notebook差不多。