VSCode部署C/C++开发环境
本文介绍了基于 VSCode 的 C/C++ 开发环境的搭建方法。
1. VSCode简介
VSCode是微软推出的一款跨平台开源编辑器,凭借强大的第三方插件支持C/C++、Python、Java等众多语言,体积小巧功能丰富,适合小型工程项目的开发调试。下面简单介绍VSCode开发环境的部署。
注意,VSCode仅仅是一个前端文本编辑器,本质上与记事本并无不同,在没有插件和编译器的情况下只能进行文件的读写,并不能进行源程序编译调试。与之相对,微软自家的Visual Studio是一个集成开发环境(IDE),下载安装后可以直接进行源程序的编译调试。
从源代码转换为可执行程序的完整过程,也就是我们俗称的编译过程。经过几十年的发展,如今标准的编译过程如下:
- 源代码 (source code) =>
- 预处理器 (preprocessor) =>
- 编译器 (compiler) =>
- 汇编程序 (assembler) =>
- 目标代码 (object code) =>
- 链接器 (Linker) =>
- 可执行文件 (executables)
VSCode 本身仅仅是一个源代码编辑器。不过,当配合插件和编译器后,VSCode也能够完成绝大部分的源代码编译调试工作。
2. VSCode下载与安装
前往官网(https://code.visualstudio.com)下载安装,支持Windows、Linux和Mac系统。可以下载安装版,也可以选择解压即用的绿色版。区别在于安装板会向系统路径写入配置信息,绿色版所有的依赖信息和配置信息均存放于一个目录中。安装版可以在线下载更新和安装更新,绿色版只能下载新版本的绿色安装包解压后覆盖来更新。
安装完成后,点击左侧的扩展商店,搜索chinese,下载中文简体汉化包(可能需要翻墙)。
安装完成后重启VSCode,即可发现所有界面均已汉化。
注意:
-
VSCode基于文件夹进行编译和调试,每个项目必须对应一个文件夹作为工作路径(根目录),根目录内包含一个.vscode文件夹存放配置文件(json格式);
-
VSCode默认编码为UTF8,对中文支持并不完美,特别是打开已有的包含中文注释的源代码文件时要特别注意,可能导致中文乱码,且在保存文件时弹出警告。因此,对于包含中文注释的已有文件,一般需要新建一个空白文件,保存为UTF8编码格式,然后重新输入中文注释部分再进行保存。
3. 配置C/C++开发环境
基于 VSCode 进行 C/C++ 项目开发,首先需要安装C/C++的VSCode扩展。扩展商店搜索“C”,安装微软官方出品的C/C++扩展。然后重启VSCode。
安装扩展完毕后,需要安装一款 C/C++ 编译器进行项目编译。C/C++ 编译器种类众多,主要包括 GCC 家族,MSC 家族,Clang 和其他编译器:
- GCC 家族(GNU Compiler Collection)
GNU C++
:GCC家族的根本,其他编译器均从此导出Cygwin
:WIN32平台下的类UNIX环境,包含编译器Mingw32
:WIN32平台的GCC编译器,仅32位,停止更新Mingw32-w64
:WIN32平台的GCC编译器,代替Mingw32
- MSVC 家族(Microsoft C/C++)
MSVC
:微软 VS IDE 的编译器
- LLVM-Clang 家族
Clang
:基于LLVM的C/C++编译器,主要面向苹果开发
- Borland 家族
TC/TC++
BC
- 其他
Intel C/C++
Watcom C/C++
- …
在Windows环境下,VSCode 推荐使用 MinGW-w64 编译器或 MSVC 编译器。
3.1. MinGW-W64 编译器
3.1.1. 安装编译器
前往 MinGW-w64 官方 GitHub(https://github.com/niXman/mingw-builds-binaries/releases )选择下载并安装编译器。对于 Windows 环境,下载 MingW-W64-builds
版本,建议选择 x86_64-xx.x.0-release-posix-seh-ucrt-rt_v10-rev2.7z
版本。安装时路径必须为全英文。对于跨平台程序,MinGW-W64编译器提供最接近原生 Linux 的编译环境。
关于 MinGW-W64 各版本的额外介绍:
- 线程模型:跨平台程序选择posix,win程序(要使用WinAPI)选择win32
- [ posix ]:线程使用
pthread
的 Windows 版本。posix 是操作系统统一接口标准,不同操作系统需要提供相同的接口以方便应用移植,降低移植成本,但是只支持 POSIX 线程模型。pthread 是在 Linux 下常用的线程库,使用 posix 接口意味着应用的多线程模型移植更方便,哪怕从 Linux 下拉过来一个应用框架也可以较小代价修改代码。但在某些情况下会引起性能下降,毕竟不是 Windows 原生的线程库,C 标准可能到 C11 以上,并且支持 C11(C 语言编码标准)的特性;- [ win32 ]:使用 Windows 原生线程库,性能等方面表现更出色,兼容性更好,没有 C11 那些眼花缭乱的特性,就看你是否熟悉 Windows 相关接口。
- 异常模型:选择seh
- [ seh ]:(Structured Exception Handling)是一种在Windows下特有的异常处理机制。SEH实现了一种结构化的异常处理机制,可以在程序运行过程中捕获并处理程序错误和异常。 SEH采用了一种基于表格的编码方式,在程序运行时会根据表格内的信息来处理异常。
- [ dwarf ]:dwarf(DW2,dwarf-2)是一种跨平台的调试信息标准,主要用于UNIX/Linux平台的调试,可以提供更加详细和准确的调试信息,方便程序调试和分析。DWARF则是采用了一种基于编译器输出的调试信息格式,需要编译器在编译时生成相应的调试信息。
- [ sjlj ]:【20230517补充】最新版本的 mingw-w64 已经不再支持 sjlj 异常处理,取而代之的是 dwarf2 和 seh 两种处理机制。如果您的程序依赖于 sjlj 异常处理机制,那么您需要考虑升级或修改代码以适应 mingw-w64 的最新版本。如果您仍然想使用 sjlj 异常处理机制,那么您可以考虑使用早期版本的 mingw-w64 或者尝试其他编译器。
- C运行时:选择ucrt
- [ucrt]:最新的 MinGW 安装包新引入并采用了 Universal C Runtime (UCRT),比 Microsoft Visual C Runtime (MSVCRT)更新。MSVCRT是逐渐被UCRT取代的,因为UCRT提供了一致的API(应用程序接口)和行为,能够让开发人员使用统一的代码来处理相同的任务,不管是哪个Windows平台甚至是通过不同版本编译器编译。但 UCRT 只支持 Windows 10 及其以上的操作系统。
- [msvcrt]:MSVCRT(Microsoft Visual C++ Runtime)和UCRT(Universal C Runtime)是Microsoft Windows上的两种C标准库变体。MSVCRT在所有Microsoft Windows版本中都默认可用,但由于向后兼容性问题,它已经过时,不兼容C99并且缺少一些功能。
3.1.2. 配置 “编译-调试-运行” 链
安装完编译器后,需要配置“编译-调试-运行”链,告诉 VSCode 如何使用编译器进行编译调试运行操作。有两种配置方式,一种是使用 VSCode 原生的配置,另一种是使用 CMake 。二者的差异在于:
- VSCode 配置:基于一系列
./vscode/.json
文件完成配置,文件内容随平台和编译器不同而不同; - CMake 配置:基于
CMakeLists.txt
文件完成配置,直接随项目迁移,可实现与平台和编译器无关的项目编译调试运行,更有利于跨平台项目开发。
因此,推荐使用 CMake 进行 “编译-调试-运行” 链配置。
3.1.2.1. VSCode 配置
VSCode 提供了一系列基于 .json
文件的配置方式。这些文件存放在待开发项目的 .vscode
文件夹内。对于 C/C++ 项目,文件主要包括
1
2
3
c_cpp_properties.json //语言配置
task.json //编译配置
launch.json //调试/运行配置
-
语言配置(c_cpp_properties.json)
对于 C/C++ 语言,VSCode 专门提供了
c_cpp_properties.json
配置文件进行配置,一个使用 MinGW-W64 编译器的典型的配置如下所示:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
"configurations": [ { "name": "Win32", "includePath": [ "${default}", "${workspaceFolder}/**" ], "defines": [ "_DEBUG", "UNICODE", "_UNICODE" ], "windowsSdkVersion": "10.0.17763.0", "compilerPath": "X:/your/compile/path/g++.exe", // <--modify "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "windows-gcc-x64" } ], "version": 4 }
注意,其中与编译器有关的路径配置项需要根据自身情况更改。
-
编译配置(task.json)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
{ "version": "2.0.0", "tasks": [ { "type": "cppbuild", "label": "C/C++: g++.exe build", "command": "g++.exe", "args": [ "-fdiagnostics-color=always", "-std=c++11", // <-- user defined according to project "-g", "${workspaceFolder}/*.c", // <-- source files "${workspaceFolder}/xx/*.c", "${workspaceFolder}/*.cpp", "${workspaceFolder}/xx/*.cpp", "-I${workspaceFolder}/xx", // <-- include header files using "-Ixxxx" "-I${workspaceFolder}/xx/xx", "-I${workspaceFolder}/bbb/bb", "-o", "${workspaceFolder}/XXXX.exe", // comipled exe name "-lws2_32" // <-- link lib when using windows socket ], "options": { "cwd": "${fileDirname}" }, "problemMatcher": [ "$gcc" ], "group": "build", "detail": "C/C++: g++.exe build" // user defined } ] }
其中
std=c++11
表明项目采用 C++11 规范编译,需要根据项目情况自行修改;-g
表示后续内容是待编译的所有文件;${workspaceFolder}
是项目的根目录,项目源文件可在其基础上列写;-I
用来 include 头文件路径;*.cpp
可以使用通配符来表示某路径下所有后缀名相同的某文件,当然也可以逐一写出项目所有文件;detail
定义了编译配置的名称,用于界面显示和后续调试运行配置使用;
上述配置等价于命令行
1
g++.exe -std=c++11 -g xx/x.c xxx.c xxx.cpp -IX:/xx/xx -IX:/bbb/bb -lws2_32 -o XXXX.exe
-
调试/运行配置(launch.json)
调试配置是在编译成功后,对编译得到的可执行程序
.exe
文件进行调试/运行的过程配置,一个典型的配置如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
{ "version": "0.2.0", "configurations": [ { "name": "GCC:调试运行", "type": "cppvsdbg", "request": "launch", "program": "${workspaceFolder}/XXXX.exe", // 注意与编译配置得到的可执行文件同名 "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": true, "preLaunchTask": "C/C++: g++.exe build" //在启动调试之前默认先编译,以便生成目标程序,注意与编译任务的名称相同 }, { // used for python, can be deleted "name": "Python: 当前文件", "type": "python", "request": "launch", "program": "${file}", "console": "integratedTerminal" } ] }
其中
program
:是编译得到的可执行程序的名称,注意与编译配置中的-o
命令后的程序名称保持一致;preLaunchTask
:用来确定进行调试/运行前需要执行的任务,如果设置此项为编译任务(比如本例中的C/C++: g++.exe build
任务),可以在每次调试/运行前自动完成编译,而无需手动编译;
注意,launch.json 是一个跨语言通用的配置文件,意味着不仅仅 C/C++ 使用该文件,其他语言如 Python 也使用该配置文件进行代码解释配置。不同语言的配置通过大括号分隔开,并根据用户自定义的配置名称
"name": "xxxx"
来进行区分。 -
编译调试运行
打开任意工程项目源文件,如
hello.cpp
,同时按下快捷键Ctrl + Shift + B
。VSCode会启动生成任务并在终端中显示其生成过程。生成完毕后,按F5
进行调试运行,可在终端中查看运行结果。至此,我们完成了全部的C/C++开发环境部署。
3.1.2.2. CMake 配置
CMake(官网:https://cmake.org)是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性。CMake 允许开发者编写一种平台无关的 CMakeLists.txt
文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到 “Write once, run everywhere”。
-
安装 CMake
在 Windows 环境下,直接前往官网下载最新的安装包安装。可以通过
cmake --version
查看版本来确认安装是否成功。在 VScode 中,安装以下两个插件:
- CMake
- CMake Tools
在 Cmake Tools 插件设置中将 Cmake 的
make.exe
可执行程序完整路径设置到cmake.cmakePath
。同时将 make.exe 所在的路径添加到系统的环境变量中。 - 配置 CMakeLists.txt
若只需要对他人项目进行编译,则可跳过此步骤。若需要对自己的项目进行 CMake 配置,请继续阅读本条内容。
使用 CMake 插件创建
CMakeLists.txt
文件(文件名一个字都不能错)。两种创建方式,推荐后者:-
手动创建,直接在工程项目的根目录下新建一个
CMakeLists.txt
文件; -
自动创建,在 VSCode 中打开工程项目文件夹,输入快捷键组合
Ctrl + Shift + P
然后输入cmake quick start
进行快速设置。首次设置会弹出Select a Kit
需要选择一个编译器,若正确安装 MinGW-W64 并添加了环境变量,一般会自动检索到类似GCC XX.X.X x86-64-w64-mingw32
的编译器,注意检查后面的路径是否正确,然后选择即可。选择后即会在项目根目录下自动创建CMakeLists.txt
文件。
配置即编写
CMakeLists.txt
文件,通常一个CMakeLists.txt
文件需要包含:project(xxx)
:项目名称add_subdirectory(path)
:工程可由多个子目录组成,每个子目录可以设置自己的CMakeLists.txt
并且通过该根目录的CMakeLists.txt
通过本命令包含add_executable(XXX)
:编译得到的可执行程序名target_include_directories(path)
:头文件路径target_link_libraries(path)
:可执行程序依赖的库文件名,如各类动态链接库
-
- 构建项目
CMake默认采用 out-of-source 构建方式,即会在
CMakeLists.txt
所在的目录下(一般也就是工程项目的根目录)新建一个build
文件夹,用于存储 CMake 构建的中间文件和生成的目标文件。这种方法可以保证生成中间产物与源代码分离(即生成的所有目标文件都存储在build
文件夹中,因此不会干扰源代码中的任何文件)。 -
编译调试运行
3.2. MSVC 编译器
3.2.1. 安装编译器
MSVC 编译器即 MicroSoft Visual C/C++ 编译器(核心文件为 cl.exe
),如果下载安装了 Visual Studio 集成开发环境(如VS2022),则该编译器已经自动部署到了计算机中。采用 VSCode 作为编辑器时,可以只单独安装编译器而无需安装完整的 Visual Studio IDE。前往 Visual Studio 官网(https://visualstudio.microsoft.com/zh-hans/downloads/) ,往下拉,找到并展开 “Visual Studio 20xx 工具”,选择 “Visual Studio 20xx 生成工具”,下载并按照提示进行安装。仅安装 MSVC 编译器占用的空间远小于完整安装 VS IDE。
3.2.2. 配置 “编译-调试-运行” 链
VSCode进行编译连接等操作依赖一系列.json
格式的配置文件,这些配置文件都位于工作路径下的.vscode
文件夹内。
3.2.2.1. VSCode 配置
-
语言配置(c_cpp_properties.json)
打开VSCode,打开一个工作文件夹,写一个hello world的.cpp程序。在工作路径的根文件夹中,然后按快捷键ctrl+shift+P,搜索“c/c”,选择 “编辑配置(JSON)” 。VSCode将自动创建
.vscode/c_cpp_properties.json
配置文件。或者,我们也可以手动创建该配置文件并填充内容。根据个人安装MSVC编译器的位置不同,配置
compilerPath
路径(即cl.exe的路径)。以下图为例,除compilerPath
外,其它配置项保持与图中一致。注意,该路径也需要保存在系统的环境变量
Path
中。否则会导致cl
命令不可用。 -
编译配置(task.json)
再次ctrl+shift+P,搜索 “task”,选择 “配置默认测试任务” → “使用模板创建…” → “Others 运行任意外部命令的示例”。VSCode将会自动创建
.vscode/task.json
配置文件,我们同样也可以手动创建该文件。然后,用以下代码替换文件的所有内容:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
{ "version": "2.0.0", "tasks": [ { "label": "msvc build", "type": "shell", "command": "cl.exe", "args": [ "/I'E:\\ProgramFiles\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.25.28610\\include'", "/I'C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\shared'", "/I'C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\ucrt'", "/I'C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\um'", "/I'C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\winrt'", "/I'${workspaceFolder}\\AAA\\AAAA\\'", "/I'${workspaceFolder}\\BBB\\'", "/I'${workspaceFolder}\\'", "/nologo", "${workspaceFolder}\\CCC\\CCCC\\*.c", "${workspaceFolder}\\DDD\\*.c", "${workspaceFolder}\\EEE\\*.cpp", "${workspaceFolder}\\*.cpp", "${workspaceFolder}\\*.c", "/Zi", "/EHsc", "/Fo:${workspaceFolder}\\build\\", "/Fe:winFFF.exe", "/link", "/libpath:'E:\\ProgramFiles\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64'", "/libpath:'C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.18362.0\\ucrt\\x64'", "/libpath:'C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.18362.0\\um\\x64'" ], "group": { "kind": "build", "isDefault": true }, "presentation": { "reveal": "always" }, "problemMatcher": "$msCompile" } ] }
下面对该文件中的
"args"
进行详细解读:"/I'includepath'"
为程序依赖的头文件存放路径,/I
即include。第一条路径为MSVC编译器的头文件路径,后四条路径为Windows 10包含的头文件路径。具体路径根据个人的系统和编译器而异。这五条路径为必备的包含路径;"/I'${workspaceFolder}\\AAA\\AAAA\\'"
等等为工程项目源代码所依赖的头文件的存放路径,其中${workspaceFolder}
为项目的工作路径根目录,AAA和AAAA为项目自定义的文件夹名,根据个人项目的具体情况设置。后面的BBB、CCC等类似;"/nologo"
表示取消显示版权标志在编译器启动时和在编译期间显示信息性消息;"${workspaceFolder}\\CCC\\CCCC\\*.c",
等等表示项目包含的需要编译的源代码文件(.c,.cpp);"/Zi"
选择为程序创建的调试信息的类型,此处将此信息保存在程序数据库(PDB)中;"/EHsc"
选择异常处理模型,此处为同步异常处理模型;"/Fo:${workspaceFolder}\\build\\",
设置创建的.object
文件的存放路径,此处为工作路径下的build文件夹;"/Fe:winFFF.exe"
设置生成的可执行文件.exe
的名称,此处为winFFF.exe
;"/link"
传输指定的参数给link,此处表示将后面的路径传递给连接器用于连接;"/libpath:'winlibpath'"
为 Window 10 的库文件存放路径,根据Windows环境而异。这三条路径为必备的库文件路径;
以一个最简单的一个hello world程序为例,源代码文件名为
hello.cpp
,相应的task.json
文件中的"args"
如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
"args": [ "/I'D:\\Programs\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\include'", "/I'C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\shared'", "/I'C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\ucrt'", "/I'C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\um'", "${workspaceFolder}\\hello.cpp", "/Zi", "/EHsc", "/Fo:${workspaceFolder}\\hello.obj", "/Fe:${workspaceFolder}\\hello.exe", "/link", "/libpath:'D:\\Programs\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\lib\\x64'", "/libpath:'C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.18362.0\\ucrt\\x64'", "/libpath:'C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.18362.0\\um\\x64'" ],
其中,
hello.cpp
也可以采用通配符的形式写为*.cpp
,方便后续扩展。 -
调试配置(launch.json)
点击 “调试” 图标菜单,选择 “添加配置” => “C++(Windows)” => “Default Configuration”,VSCode将自动创建
launch.json
文件,同样也可以手动创建该配置文件。用以下内容替换该文件的全部默认内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
{ "version": "0.2.0", "configurations": [ { "name": "MSVC: 运行", "type": "cppvsdbg", "request": "launch", "program": "${workspaceFolder}/winFFF.exe", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": true } ] }
注意,
program
字段中的可执行文件名,必须与前面tasks.json
中args
字段的"/Fe:"
参数完全一致(此处均为winFFF.exe
)。至此,完成所有配置文件的生成。需要提醒的是,VSCode是基于工作路径进行编译调试的,若需要在其他文件夹(项目)中使用已有的配置时,只需要将当前的
.vscode
子文件夹复制到该项目的工作路径下,然后修改其中相应的参数项(如C/C++文件路径、可执行文件名称等)即可。 -
编译调试运行 与前面 MinGW 编译器类似。官方同样给出了详细的基于MSVC编译器的开发环境部署方法,见参考文献[1]。
3.2.2.2. CMake 配置
Working in Progress.
5. VSCode 快捷键
Ctrl + Shift + N
新建一个 VSCode 窗体
Alt + left/right
回到上/下一个光标停留的位置
Ctrl + Shift + P
调出执行命令的输入面板
Ctrl + ,
调出设置面板
Ctrl + K, Ctrl + 0
折叠所有代码块
Ctrl + K, Ctrl + J
展开所有代码块
6. 参考文献
[1] Micsosoft. Configure VS Code for Microsoft C++.