在 VS Code 中尝试

在 VS Code 中使用 C++ 和 WSL

在本教程中,你将配置 Visual Studio Code,以便在 适用于 Linux 的 Windows 子系统 (WSL) 中的 Ubuntu 上使用 GCC C++ 编译器 (g++) 和 GDB 调试器。GCC 代表 GNU Compiler Collection;GDB 是 GNU 调试器。WSL 是 Windows 中的一个 Linux 环境,它直接运行在机器硬件上,而不是虚拟机中。

注意:本教程的大部分内容也适用于直接在 Linux 机器上使用 C++ 和 VS Code。

Visual Studio Code 通过 WSL 扩展 支持直接在 WSL 中工作。我们推荐这种 WSL 开发 模式,在此模式下,你的所有源代码文件以及编译器都托管在 Linux 发行版上。更多背景信息,请参阅 VS Code 远程开发

完成本教程后,你就可以创建和配置自己的 C++ 项目,并探索 VS Code 文档以获取更多关于其众多功能的信息。本教程不教授 GCC、Linux 或 C++ 语言。对于这些主题,网上有许多很好的资源。

如果你遇到任何问题,请随时在 VS Code 文档存储库 中为此教程提出问题。

先决条件

要成功完成本教程,必须执行以下步骤

  1. 安装 Visual Studio Code

  2. 安装 WSL 扩展

  3. 安装 适用于 Linux 的 Windows 子系统,然后使用同一页面上的链接安装你选择的 Linux 发行版。本教程使用 Ubuntu。安装过程中,请记住你的 Linux 用户密码,因为安装附加软件时需要用到它。

设置 Linux 环境

  1. 打开 WSL 的 Bash shell。如果你安装了 Ubuntu 发行版,请在 Windows 搜索框中键入“Ubuntu”,然后在结果列表中单击它。对于 Debian,键入“Debian”,依此类推。

    Ubuntu in Start Menu

    Shell 会出现一个命令提示符,默认包含你的用户名和计算机名,并将你置于主目录中。对于 Ubuntu,它看起来像这样

    Bash Shell

  2. 创建一个名为 projects 的目录,然后在该目录下创建一个名为 helloworld 的子目录

    mkdir projects
    cd projects
    mkdir helloworld
    
  3. 尽管你将使用 VS Code 编辑源代码,但你将在 Linux 上使用 g++ 编译器编译源代码。你还将使用 GDB 在 Linux 上进行调试。这些工具在 Ubuntu 上默认未安装,因此你必须安装它们。幸运的是,这项任务相当容易!

  4. 从 WSL 命令提示符中,首先运行 apt-get update 以更新 Ubuntu 软件包列表。过时的发行版有时会干扰安装新软件包的尝试。

    sudo apt-get update
    

    如果你愿意,可以运行 sudo apt-get update && sudo apt-get dist-upgrade 来同时下载最新版本的系统软件包,但这可能需要更长的时间,具体取决于你的连接速度。

  5. 从命令提示符中,通过键入以下命令安装 GNU 编译器工具和 GDB 调试器

    sudo apt-get install build-essential gdb
    
  6. 通过查找 g++ 和 gdb 来验证安装是否成功。如果 whereis 命令未返回文件名,请尝试再次运行更新命令。

    whereis g++
    whereis gdb
    

注意:如果你直接在 Linux 机器上工作而不是在 WSL 中工作,安装 g++ 编译器和 GDB 调试器的设置步骤也适用。在 helloworld 项目中运行 VS Code,以及编辑、构建和调试步骤都是相同的。

在 WSL 中运行 VS Code

导航到你的 helloworld 项目文件夹,并在 WSL 终端中用 code . 启动 VS Code。

cd $HOME/projects/helloworld
code .

你会看到一条关于“正在安装 VS Code Server”的消息。VS Code 正在 Linux 端下载和安装一个小型服务器,桌面版 VS Code 随后将与其通信。然后,VS Code 将启动并打开 helloWorld 文件夹。文件资源管理器显示 VS Code 现在在 WSL 上下文中运行,标题栏为 WSL: Ubuntu

File Explorer in WSL

你也可以从状态栏中得知远程上下文。

Remote context in the Status bar

如果点击远程状态栏项,你会看到一个适用于当前会话的远程命令下拉列表。例如,如果你想结束在 WSL 中运行的会话,可以从下拉列表中选择 关闭远程连接 命令。从 WSL 命令提示符运行 code . 将在 WSL 中重新启动 VS Code。

code . 命令在当前工作文件夹中打开 VS Code,该文件夹成为你的“工作区”。通过本教程,你将在工作区的一个 .vscode 文件夹中看到创建三个文件

  • c_cpp_properties.json(编译器路径和智能感知设置)
  • tasks.json(构建指令)
  • launch.json(调试器设置)

添加源代码文件

在文件资源管理器标题栏中,选择 新建文件 按钮并将文件命名为 helloworld.cpp

New File title bar button

安装 C/C++ 扩展

创建文件后,VS Code 会检测到它是 C++ 语言文件,如果尚未安装,可能会提示你安装 Microsoft C/C++ 扩展

C++ extension notification

当扩展视图中显示按钮时,选择 安装,然后选择 需要重新加载,以完成 C/C++ 扩展的安装。

如果你已经在本地 VS Code 中安装了 C/C++ 语言扩展,你需要前往扩展视图 (⇧⌘X (Windows, Linux Ctrl+Shift+X)) 并将这些扩展安装到 WSL 中。可以通过选择 在 WSL 中安装 按钮,然后选择 需要重新加载,将本地安装的扩展安装到 WSL 中。

Install in WSL button

添加 helloworld 源代码

现在粘贴以下源代码

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
   vector<string> msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"};

   for (const string& word : msg)
   {
      cout << word << " ";
   }
   cout << endl;
}

现在按 ⌘S (Windows, Linux Ctrl+S) 保存文件。注意你刚刚添加的文件如何出现在 VS Code 侧边栏的 文件资源管理器 视图 (⇧⌘E (Windows, Linux Ctrl+Shift+E)) 中

File Explorer

你还可以通过在主菜单 文件 中勾选 自动保存 来启用 自动保存,以自动保存文件更改。

最左边的活动栏允许你打开不同的视图,例如 搜索源代码管理运行。稍后在本教程中,你将查看 运行 视图。你可以在 VS Code 用户界面文档 中了解有关其他视图的更多信息。

探索智能感知

在新的 helloworld.cpp 文件中,将鼠标悬停在 vectorstring 上,查看类型信息。在声明 msg 变量后,开始输入 msg.,就像调用成员函数一样。你应该立即看到一个完成列表,其中显示了所有成员函数,以及一个显示 msg 对象类型信息的窗口

Statement completion IntelliSense

你可以按 Tab 键插入选中的成员;然后,当你添加左括号时,你将看到有关函数所需的任何参数的信息。

运行 helloworld.cpp

请记住,C++ 扩展使用你在机器上安装的 C++ 编译器来构建你的程序。在尝试在 VS Code 中运行和调试 helloworld.cpp 之前,请确保已安装 C++ 编译器。

  1. 打开 helloworld.cpp,使其成为活动文件。

  2. 单击编辑器右上角的播放按钮。

    Screenshot of helloworld.cpp and play button

  3. 从系统检测到的编译器列表中选择 g++ 构建并调试活动文件

    C++ debug configuration dropdown

你只会在第一次运行 helloworld.cpp 时被要求选择编译器。此编译器将在 tasks.json 文件中设置为“默认”编译器。

  1. 构建成功后,程序的输出将显示在集成 终端 中。

    screenshot of program output

第一次运行程序时,C++ 扩展会创建 tasks.json,该文件位于项目的 .vscode 文件夹中。tasks.json 存储构建配置。

新的 tasks.json 文件应与下面的 JSON 类似

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "C/C++: 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
      },
      "detail": "Task generated by Debugger."
    }
  ]
}

注意:你可以在变量参考中了解更多关于 tasks.json 变量的信息。

command 设置指定要运行的程序;在此示例中为 g++。args 数组指定将传递给 g++ 的命令行参数。这些参数必须按照编译器期望的顺序指定。

此任务告诉 g++ 接受活动文件(${file}),对其进行编译,并在当前目录(${fileDirname})中创建一个可执行文件,该文件的名称与活动文件相同,但没有扩展名(${fileBasenameNoExtension}),例如将生成 helloworld

label 值是你在任务列表中看到的名称;你可以将其命名为你喜欢的任何名称。

detail 值是你在任务列表中看到的任务描述。强烈建议重命名此值,以区分类似任务。

从现在开始,播放按钮将读取 tasks.json 以确定如何构建和运行你的程序。你可以在 tasks.json 中定义多个构建任务,标记为默认值的任务将被播放按钮使用。如果你需要更改默认编译器,可以运行 Tasks: 配置默认构建任务。或者,你可以修改 tasks.json 文件,通过替换此片段来移除默认设置

    "group": {
        "kind": "build",
        "isDefault": true
    },

替换为以下内容

    "group": "build",

修改 tasks.json

你可以修改 tasks.json,使用类似 "${workspaceFolder}/*.cpp" 的参数来构建多个 C++ 文件,而不是使用 "${file}"。这将构建当前文件夹中的所有 .cpp 文件。你也可以通过将 "${fileDirname}/${fileBasenameNoExtension}" 替换为硬编码的文件名(例如 'helloworld.out')来修改输出文件名。

调试 helloworld.cpp

要调试代码,

  1. 返回到 helloworld.cpp,使其成为活动文件。
  2. 通过单击编辑器边距或在当前行使用 F9 设置断点。 helloworld.cpp 中的断点屏幕截图
  3. 从播放按钮旁边的下拉菜单中,选择 调试 C/C++ 文件播放按钮下拉菜单屏幕截图
  4. 从系统检测到的编译器列表中选择 C/C++: g++ 构建并调试活动文件(你只会在第一次运行或调试 helloworld.cpp 时被要求选择编译器)。 C++ 调试配置下拉菜单

播放按钮有两种模式:运行 C/C++ 文件调试 C/C++ 文件。它将默认为上次使用的模式。如果你在播放按钮中看到调试图标,则可以单击播放按钮进行调试,而无需选择下拉菜单项。

探索调试器

在你开始单步执行代码之前,让我们花点时间注意用户界面的几个变化

  • 集成终端出现在源代码编辑器的底部。在 调试输出 选项卡中,你看到指示调试器已启动并运行的输出。

  • 编辑器突出显示第 12 行,这是你在启动调试器之前设置的断点

    Initial breakpoint

  • 左侧的 运行和调试 视图显示调试信息。稍后在本教程中,你将看到一个示例。

  • 在代码编辑器的顶部,出现一个调试控制面板。你可以通过抓取左侧的点来在屏幕上移动它。

    Debugging controls

如果你已经在工作区中拥有一个 launch.json 文件,播放按钮将在确定如何运行和调试 C++ 文件时从中读取。如果你没有 launch.json 文件,播放按钮将即时创建一个临时的“快速调试”配置,从而完全无需 launch.json!

单步执行代码

现在你已准备好开始单步执行代码。

  1. 单击或按调试控制面板中的 跳过 图标。

    Step over button

    这将使程序执行前进到 for 循环的第一行,并跳过创建和初始化 msg 变量时调用的 vectorstring 类内的所有内部函数调用。注意左侧 变量 窗口的变化。

    Debugging windows

  2. 再次按 跳过,前进到程序中的下一条语句(跳过初始化循环时执行的所有内部代码)。现在,变量 窗口显示有关循环变量的信息。

  3. 再次按 跳过,执行 cout 语句。(注意,C++ 扩展在最后一个 cout 执行之前不会将任何输出打印到 调试控制台。)

  4. 如果你愿意,可以继续按 跳过,直到向量中的所有单词都打印到控制台。但如果你感到好奇,请尝试按 步进 按钮来单步执行 C++ 标准库中的源代码!

    Breakpoint in gcc standard library header

    要返回到自己的代码,一种方法是继续按 跳过。另一种方法是在代码编辑器中切换到 helloworld.cpp 选项卡,将插入点放在循环内的 cout 语句的某个位置,然后按 F9。左侧的边栏中会出现一个红点,表示在该行设置了断点。

    Breakpoint in main

    然后按 F5 从标准库头文件中的当前行开始执行。执行将在 cout 处中断。如果你愿意,可以再次按 F9 来切换关闭断点。

    循环完成后,你可以在集成终端的 调试控制台 选项卡中看到输出,以及 GDB 输出的一些其他诊断信息。

    Debug console display

设置监视

要在程序执行过程中跟踪变量的值,请对变量设置 监视

  1. 将插入点置于循环内。在 监视 窗口中,点击加号并在文本框中输入 word,这是循环变量的名称。现在,在单步执行循环时查看监视窗口。

    Watch window

  2. 要在执行在断点处暂停时快速查看任何变量的值,可以将鼠标指针悬停在其上方。

    Mouse hover

接下来,你将创建一个 tasks.json 文件,告诉 VS Code 如何构建(编译)程序。此任务将调用 g++ 编译器从源代码创建可执行文件。

务必在编辑器中打开 helloworld.cpp,因为下一步将使用编辑器中的活动文件作为上下文,在下一步中创建构建任务。

使用 launch.json 自定义调试

当你使用播放按钮或 F5 进行调试时,C++ 扩展会即时创建一个动态调试配置。

在某些情况下,你可能需要自定义调试配置,例如指定运行时要传递给程序的参数。你可以在 launch.json 文件中定义自定义调试配置。

要创建 launch.json,从播放按钮下拉菜单中选择 添加调试配置

Add debug configuration play button menu

然后你会看到一个包含各种预定义调试配置的下拉菜单。选择 g++ 构建并调试活动文件

C++ debug configuration dropdown

VS Code 会创建一个 launch.json 文件,它看起来像这样

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "C/C++: g++ build and debug active file",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}/${fileBasenameNoExtension}",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "/usr/bin/gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "C/C++: g++ build active file"
    }
  ]
}

在上面的 JSON 中,program 指定要调试的程序。这里将其设置为活动文件所在的文件夹 ${fileDirname} 和不带扩展名的活动文件名 ${fileBasenameNoExtension},如果 helloworld.cpp 是活动文件,则将是 helloworldargs 属性是一个数组,其中包含要在运行时传递给程序的参数。

默认情况下,C++ 扩展不会向你的源代码添加任何断点,并且 stopAtEntry 的值设置为 false

stopAtEntry 的值更改为 true,以使调试器在你开始调试时在 main 方法处停止。

从现在开始,播放按钮和 F5 在启动程序进行调试时,将从你的 launch.json 文件中读取配置。

C/C++ 配置

如果你想对 C/C++ 扩展进行更多控制,可以创建一个 c_cpp_properties.json 文件,它允许你更改编译器路径、包含路径、C++ 标准(默认为 C++17)等设置。

你可以通过命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 运行命令 C/C++: 编辑配置 (UI) 来查看 C/C++ 配置 UI。

Command Palette

这将打开 C/C++ 配置 页面。当你在此处进行更改时,VS Code 会将它们写入 .vscode 文件夹中一个名为 c_cpp_properties.json 的文件。

Command Palette

只有当你的程序包含不在工作区或标准库路径中的头文件时,才需要修改 Include path 设置。

Visual Studio Code 将这些设置放在 .vscode/c_cpp_properties.json 中。如果你直接打开该文件,它应该看起来像这样

{
  "configurations": [
    {
      "name": "Linux",
      "includePath": ["${workspaceFolder}/**"],
      "defines": [],
      "compilerPath": "/usr/bin/gcc",
      "cStandard": "c11",
      "cppStandard": "c++17",
      "intelliSenseMode": "clang-x64"
    }
  ],
  "version": 4
}

关闭 WSL 会话

完成 WSL 中的工作后,可以通过主菜单 文件 和命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 中提供的 关闭远程连接 命令关闭远程会话。这将重新启动 VS Code 在本地运行。你可以通过选择带有 [WSL] 后缀的文件夹,轻松地从 文件 > 打开最近的 列表中重新打开 WSL 会话。

后续步骤

  • 探索 VS Code 用户指南
  • 查阅 C++ 扩展概述
  • 创建一个新的工作区,将你的 .json 文件复制到其中,调整新工作区路径、程序名称等必要的设置,然后开始编写代码!