Windows系统中vscode+MSVC的C++配置
在Windows上编译C++程序不能直接使用gcc和g++命令,一般来说如果非要使用的话可以用wsl或者MinGW。过去的很长一段时间我也确实是这么做的,但是最近在学习C++20,无奈MSVC是三大主流编译器里面相关特性支持最完善的,只能捣鼓一下怎么使用,特此记录。
安装Visual Studio
MSVC可以直接通过安装Visual Studio获取,在该页面选择合适的Visual Studio版本(一般来说是选社区版,因为是免费的)就可以下载安装。
其中MSVC工具链通过选择“使用C++的桌面开发”安装:
安装完之后,如果使用默认的安装位置,应该在C:\Program Files (x86)\Microsoft Visual Studio\20xx\Community\VC\Tools\MSVC\xx.xx.xx\bin\Hostx64\x64\
这个路径下面有编译链包含的各个工具(比如cl.exe
)。
配置环境变量
虽然说我们找到了编译链工具的所在位置,但是如果现在直接调用它们进行编译是无法正常运行的,这是因为MSVC工具链还有很多额外的环境变量配置。这些变量当然可以手动配置,但是Visual Studio本身提供了一个配置脚本:C:\Program Files (x86)\Microsoft Visual Studio\20xx\Community\VC\Auxiliary\Build\vcvars64.bat
,这个bat
脚本中干的事情就是把那些杂七杂八的环境变量给设置好。
因此我只把这个脚本所在的文件夹加入了Path
环境变量,这样一来只需在cmd
中先调用vcvars64
,就可以正常使用cl.exe
等编译工具了:
C:\Users\xxx>where cl
INFO: Could not find files for the given pattern(s).
C:\Users\xxx>vcvars64
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.11.22
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
C:\Users\xxx>where cl
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe
不过这个脚本比较坑,必须用cmd
命令行才能运行,在powershell
命令行中是无效的(而且依然会有配置成功的输出,真坑)。
其实这个时候就可以使用cl.exe
直接进行C++源文件的编译了,比如现在有一份main.cpp
:
#include <iostream>
int main() {
std::cout << "hello" << std::endl;
return 0;
}
使用命令cl.exe /EHsc /std:c++20 main.cpp
就可以编译得到文件main.exe
,运行后输出hello
:
C:\Users\xxx>type main.cpp
#include <iostream>
int main() {
std::cout << "hello" << std::endl;
return 0;
}
C:\Users\xxx>cl /EHsc /std:c++20 main.cpp
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.29.30147 版
版权所有(C) Microsoft Corporation。保留所有权利。
main.cpp
Microsoft (R) Incremental Linker Version 14.29.30147.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
C:\Users\xxx>.\main.exe
hello
所以说使用MSVC也不难。既然搞清楚了原理,就可以去编写vscode的相关文件(launch.json
和tasks.json
),然后让vscode也能一键使用MSVC编译运行源代码。
配置launch.json
和tasks.json
在安装了C++插件之后,使用vscode打开C++源文件会在右上角显示一个小三角形,按下它就会打开编译运行的选择列表:
这个列表里面有的项是默认配置的(比如上图的后面四个)。一般来说这个时候是会显示像上图一样的那个使用cl.exe
编译的默认配置项,但是其实这个是没法用的(需要在命令行中先调用vcvars64.bat
,然后再调用code
编辑代码,太麻烦)。
上图中我的vscode显示了一个我自定义的配置(也就是第一项),这个其实是在项目根目录的.vscode
文件夹中的launch.json
和tasks.json
中定义的:
launch.json
中有一个configurations
列表,其中的项就是用户自定义的那些调试启动项,先放出我最终的文件:
{
"configurations": [
{
"name": "C/C++: 运行活动文件(自定义)",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:\\Program Files\\mingw64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: 生成活动文件(自定义)"
}
],
"version": "2.0.0"
}
其中name
就是会在表项中显示的名字,注意不要含有cl.exe
字样,因为当前版本的vscode似乎是直接通过命名进行检测的,如果发现名字里面有cl.exe
,而你又不是先调用vcvars.bat
再调用code
的,vscode就直接不让你运行这个任务(我真是呃呃)。
type
值为cppdbg
,就表示这个配置项适用于C++源文件。后面的MIMode
,miDebuggerPath
等都是对gdb
的配置,这里我就继续沿用了MinGW的gdb
。
program
就是要运行的编译后的文件名。那么要得到这个exe
文件,就要先进行编译。编译的步骤定义在tasks.json
中,上面的preLaunchTask
就是在指定先运行tasks.json
中定义的name
为C/C++: 生成活动文件(自定义)
的预编译任务,该任务完成后再执行launch.json
中指定的指令。
tasks.json
与launch.json
的结构大差不差,有个tasks
列表列出各个预编译任务:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: 生成活动文件(自定义)",
"command": "cmd",
"args": [
"/c",
"vcvars64 && cl /EHsc /std:c++20 ${file}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [ ],
"group": "build",
"detail": "编译器生成的任务。"
}
],
"version": "2.0.0"
}
因为我的vscode默认终端是powershell
,不能直接调用vcvars64.bat
,所以只能通过cmd /c
的方式开一个cmd
子进程运行,/c
就是表示cmd
直接运行后面接的指令。而后面接的具体指令是vcvars64 && cl /EHsc /std:c++20 ${file}
,&&
是连接符,表示左边的命令正常完成之后执行右边的命令,所以其实它干的事情就是先调用vcvars64
设置好各个环境变量,然后再调用cl
编译vscode当前打开的C++源文件。
测试
完成上述操作之后,就可以直接点vscode右上角的三角形按钮一键使用MSVC编译运行C++程序了(另:也可以使用快捷键F5)。
另外,当前vscode的官方C++插件是默认不开启C++20相关特性的支持的,虽然说不影响编译和运行,但是写代码的时候一堆波浪线和智能提示还是让人很不爽。其实只需在settings.json
中加入一项:"C_Cpp.default.cppStandard": "c++23"
就可以开启C++20特性的支持了。
本人编写了一个简单的用到concept
特性的代码,模拟实现了python
中的enumerate
函数,都是可以正常编译运行的:
#include <iostream>
#include <vector>
template <typename T>
concept Iterable = requires(T x) { x.begin(); x.end(); };
template <Iterable T>
class enumerate {
int start;
T obj;
using _T_Iter = decltype(obj.begin());
class _Iter {
int index;
_T_Iter iter;
public:
_Iter(int index, _T_Iter iter): index(index), iter(iter) {}
void operator ++ () { ++iter, ++index; }
void operator ++ (int) { ++iter, ++index; }
auto operator * () { return std::pair(index, *iter); }
bool operator == (const _Iter& i) const { return iter == i.iter; }
bool operator != (const _Iter& i) const { return iter != i.iter; }
};
public:
enumerate(T obj, int start = 0): obj(std::move(obj)), start(start) {}
auto begin() { return _Iter(start, obj.begin()); }
auto end() { return _Iter(start, obj.end()); }
};
int main() {
std::vector vec = {1, 4, 8, 9};
for (auto [index, item]: enumerate(vec)) {
std::cout << "[" << index << "] " << item << std::endl;
}
return 0;
}