一。为什么放弃在Visual Studio IDE下Coding?
- PC有点拉跨,启动Visual Studio加载环境较慢,PC上装了多套VS,旧版本加载速度还行,但较新的版本如Visual Studio 2019,频繁地“无法响应并等待”太捉急
- VSCode是一款相当优秀的编辑器,有强大的插件支持,简单说就是在其下Coding,效率起飞
- 由于第2点描述,其他日常编码工作如shell脚本、golang等已全面切换至VSCode,想要All in One
二。那么,开始配置前,需要了解和做些什么?
- VSCode是且只是编辑器,虽然通过插件的支持可以进行构建和调试项目,但它不是IDE,它的天职是编辑,至于构建过程如编译链接就该给谁做就给谁做好了
- 安装VSCode与必要插件,
三。*踩坑摸索
- 网上查资料看有没类似案例,残念,要么大部分都是配置mingw,链接没点开直接弃;要么是按照VSCode官方配置MSVC,见Configure Visual Studio Code for Microsoft C++,概览后直接弃,单纯不喜欢,只想启动VSCode直接有个干净的开发环境,想写C++写C++,想写脚本写脚本,想让我通过开发环境命令行启动VSCode?不可能的;最后在一位国外老哥的一篇配置文章中,见https://dev.to/masoudr/build-and-debug-c-application-with-vscode-and-msvc-pfc,看到了些许希望,开坑
- 坑很大,填一个又来一个,边填边学,
- 3个关键配置文件及其作用,lauch.json(调试启动用)、tasks.json(构建用)、c_cpp_properties.json(智能提示用),C/C++插件处理代码编写、构建、调试是三个相对独立的过程需分别看待
- 国外老哥在构建即tasks.json中直接配置以shell方式启动cl.exe编译器,这个虽然和现有项目情况不大符,公司现有项目的VS工程不会废除(只有我想用VSCode,总不能搞事情让其他同事都不用VS吧),那么VSCode里配置的编译和链接参数就要和VS工程里的保持一致,这么多的参数写进tasks.json里实在是又繁琐又容易出错;但作为hello world是可以学习到配置机制的,这时踩的第一个坑就是"聪明蛋"(cmd)对空格及特殊符号的处理(cmd菜鸡表示太难用了),因为VSCode启动task时自动调用的是cmd /d /c [command],当然终端配置的是cmd,如果配置powershell,肯定调用的是不同的命令,这里不再验证;这个/c开关可要了命了,引号总会莫名其妙丢了,最终cmd /? 去找男人,原来
(可以在第一个引号前加@进行欺骗来规避,不再赘述踩坑流程)
- 由于PC上存在多VS环境,所以一直有个念头是否加载了正确的构建环境,解决完空格问题后便开始验证,再次残念,国外老哥的build命令实际上是有问题的,
"buildCommand": "C:\\Program^ Files^ ^(x86^)\\Microsoft^ Visual^ Studio\\2019\\Enterprise\\Common7\\Tools\\VsDevCmd.bat && cl"
他用&&连接命令,但实际上达不到他想要的效果。他是想先加载构建环境,加载成功后使用构建环境里的cl编译命令,但cl执行时,环境并未加载进来,可如此验证
打开cmd.exe,执行类似命令行语句(如使用PC上的VS2010环境)
这是正确加载到了构建环境的输出,注意cl的版本信息
重新打开cmd.exe(原先的cmd窗口里已存在构建环境,所以必须重新打开一个新的cmd窗口,这里也是容易疏忽踩坑的地方),再次执行命令行语句
cl却无法正确识别,说明cl执行时环境加载失败,原因未找到详细解释,应该和cmd批处理机制有关,未深究;实际上我一开始执行此命令是成功的,原因是安装VS2015的时候自动设置了PATH变量,所以cl调用的是VS2015的开发环境里cl命令,现在PATH里删除了该配置固报错,这也是前文提示注意cl版本信息的原因
尽管外国老哥的build命令存在问题,但却提供了构建思路,即先加载构建环境,然后调用构建工具,这也与VSCode官方方式通过开发环境cmd启动VSCode的描述相吻合;由于受到项目等种种约束,我这里的构建方式也明确下来了
- VSCode启动定制的外部构建脚本,把构建工作交给脚本,脚本里调用VS工程命令行工具进行构建,这样因为VS工程文件必须存在,也就不必把繁琐的编译链接参数写进VSCode配置文件,但新增文件时就需要注意,一定要把它加进VS工程文件里
- 构建的坑填完后,就是智能提示intellisense了,根据官方描述c_cpp_properties.json reference进行配置,这里主要是配置编译器路径(compilerPath)这个选项,配置后intellisense会查询编译器确定系统include目录以及预定义宏,由于PC上存在多VS环境,而对它的查询机制又不了解,能否查询到正确的include就是个未知数,而且VS2015与VS2019可以选择windows sdk版本,依赖的include路径是不同的,虽然可以在c_cpp_properties.json里配置windows sdk版本,但我填写VS2015里winsdk 8.1版本时,include路径是不对的,可在cpp里写个printf语句,然后看跳转到其函数声明文件路径即可判定,所以我放弃通过编译器查询,手撸,把include路径写进settings.json里,然后使用配置的值即可,是一次性配置,以后直接引用;确定这些路径也很简单,这里以VS2010为例,
- 调试的坑主要就是输出内容到终端这个了,按照国外老哥的配置,只有程序运行结束时,才会把打印内容输出到调试控制台,这是无法接受的,可通过配置launch.json里的console值,把打印输出到其他终端来解决,我选择了externalTerminal,可根据需要调整这个值
- 至此,与最终方案相关的坑就基本填完了,中间当然出现更多与此方案无关的坑,比如我曾试图通过调用编译链接器来完成构建,但配置的每个task都要单独加载构建环境,而不能统一加载进来供多个task共享,这个环境继承问题是插件不支持的;这些坑就不再赘述
四。开搞
1.编写外部构建脚本
- 在PC上找到所需Visual Studio加载开发环境的启动脚本,我这里配置了项目常用的VS2010和VS2015
- 根据启动脚本的USAGE用法,确定构建脚本加载环境部分的传参
- 确定用来构建VS工程的命令行命令,主要是devenv(Devenv command line switches - Visual Studio (Windows) | Microsoft Learn)与MSBuild(MSBuild on the command line - C++ | Microsoft Learn),我这里选择MSBuild,因为在测试中,devenv的加载速度有些慢,尤其是VS2015环境,而且MSBuild支持的参数更丰富,定制能力更强,devenv与MSBuild的区分不再赘述,可参考微软官方文档
- 完善构建脚本的传参与校验
- 环境加载调用:call /path/to/init/vc/env.bat
- 构建命令调用:MSBuild …
2.settings.json配置自定义变量
- 用户区(userspace settings)自定义变量,这里定义的变量几乎不会变动,一次性配置
主要关注几个使用绝对路径而未引用VSCode配置变量的地方,用来配置intellisense系统include,以及外部构建脚本build-vs.bat路径
- 工作区(workspace settings)自定义变量,这里定义的变量随工程变动而变动
其中,
Project.Builder -- 使用哪个VS版本进行构建
Project.SlnFile -- 工程sln文件名,这里自动设置为工作目录名.sln,一般工程名与目录名相同
Project.Target -- 工程目标文件,这里自动设置为工作目录名.exe,一般目标文件名与目录名相同
Project.Include -- 工程include目录,会与系统配置的include目录一起配置intellisense的include路径
Project.Debug.CWD -- 调试程序启动时的当前工作目录,一般设置为生成最终目标文件的目录,如Debug,里面包含调试所需的pdb文件
Project.Debug.Program -- 调试目标程序名
Project.Debug.Args -- 目标程序的传参
Project.Debug.PreTask -- 调试程序启动前置task标识,根据tasks.json来设置
C_Cpp.default.* -- 用来配置intellisense相关配置,我这里是想把所有要变动的配置都配置在一个文件里,剩下的配置都是几乎不动的,所以写在settings.json里,当然都是可以配置进c_cpp_properties.json里的;如果想全都要,成,在c_cpp_properties.json配置项里使用${default}里引用C_Cpp.default相对应的值
3.tasks.json配置构建任务
这里配置构建task,以shell的形式执行外部构建脚本,其中,
label -- task标识
command -- 外部构建脚本,在userspace settings.json里配置的变量
args -- 外部构建脚本传参,在workspace settings.json里配置的相关变量
options->cwd -- 运行构建脚本时的当前工作目录,即工程目录,因为其包含了sln文件,这样就不用指定sln文件的绝对路径
4.launch.json配置调试启动
这里配置调试器启动配置,其中,
type -- cppvsdbg,windows c++调试器
request -- launch,启动,还可以配置attach,是附加到现有进程上去,这里不用
program -- 调试目标程序,在workspace settings.json里配置的变量
args -- 目标程序的传参,在workspace settings.json里配置的变量
cwd -- 调试程序启动时的当前工作目录,在workspace settings.json里配置的变量
environment -- 环境变量,如目标程序链接时是静态链接到dll的lib,而且dll又不在默认的搜索目录里,就需要把它所在的目录加入到环境变量里,不然启动目标程序的时候会因找不到dll而报错,具体追加环境变量的写法
preLaunchTask -- 调试程序启动前的前置task,在workspace settings.json里配置的变量
console -- 如果默认internalTerminal,在调试过程中的打印不会立即输出到终端上,需要等到程序运行结束才会输出;这里可选配置integratedTerminal,externalTerminal
5.*c_cpp_properties.json配置intellisense智能提示,根据官方文档配置即可,如果配置了C_Cpp.default.*,则这个文件不是必须的
6.运行调试
- 运行,会启动前置build任务
- 构建成功后,成功进入断点
- F12查看printf函数原型,路径正确,说明intellisense正确加载了include,当然F11单步调试是调试不到这里的
- 外部终端正确打印内容
- 收工
五。资源
配置文件和案例见(
https://github.com/VVVylin/vsc-debug-vsproj-msbuild)