使用 GCC 配合 MinGW

在这个教程中,你将配置Visual Studio Code,使用mingw-w64中的GCC C++编译器(g++)和GDB调试器来创建可在Windows上运行的程序。配置 VS Code 后,你将编译、运行并调试一个 Hello World 程序。

本教程不教你关于GCC、GDB、minGW-w64或C++语言的内容。对于这些主题,网上有许多优质资源。

如果你有任何问题,欢迎在VS Code文档库中提交本教程的问题。

前提条件

要成功完成本教程,你必须完成以下步骤:

  1. 安装Visual Studio Code

  2. 安装 VS Code 的 C/C++ 扩展。你可以通过在扩展视图中搜索“C++”来安装 C/C++ 扩展(⇧⌘X(Windows,Linux Ctrl+Shift+X)。

    C/C++ 扩展

安装 MinGW-w64 工具链

通过MSYS2获取最新版本的MinGW-w64,MSYS2提供了GCC、MinGW-w64及其他实用C++工具和库的最新原生构建。这将为你提供编译代码、调试和配置以配合IntelliSense所需的工具。

要安装MinGW-w64工具链,请观看此视频或按照以下步骤作:

  1. 你可以从MSYS2页面下载最新的安装程序,或者使用这个直接链接访问安装程序

  2. 运行安装程序,按照安装向导的步骤作。注意,MSYS2 需要 64 位 Windows 8.1 或更新版本。

  3. 在向导中,选择你想要的安装文件夹。把这个目录记录下来,以备后用。在大多数情况下,推荐目录是可以接受的。设置开始菜单快捷方式步骤时也是一样。完成后,确保勾选“立即运行MSYS2”框并选择完成。这会为你打开一个MSYS2终端窗口。

  4. 在这个终端中,通过执行以下命令安装 MinGW-w64 工具链:

    pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain
    
  5. 接受默认数量的包裹toolchain回车键组别。

    MYSS2安装器

  6. 进来Y当被问及是否继续安装该项目时。

  7. 添加你的MinGW-w64路径bin文件夹到 WindowsPATH环境变量通过以下步骤实现:

    1. 在Windows搜索栏输入“设置”打开Windows设置。
    2. 搜索你账户的编辑环境变量
    3. 在你的用户变量中,选择Path变量,然后选择编辑
    4. 选择新建,并将你在安装过程中录制的 MinGW-w64 目标文件夹添加到列表中。如果你用了上面的默认设置,那路径会是:C:\msys64\ucrt64\bin.
    5. 选择确定,然后在环境变量窗口再次选择确定以更新PATH环境变量。 你需要重新打开所有控制台窗口才能看到更新PATH环境变量将可用。

检查你的MinGW安装

要检查你的 MinGW-w64 工具是否正确安装并可用,请打开一个新的命令提示符并输入:

gcc --version
g++ --version
gdb --version

你应该会看到显示你安装了哪些版本的GCC、g++和GDB的输出。如果不是这样:

  1. 确保你的PATH变量条目与安装工具链的MinGW-w64二进制位置一致。如果编译器不存在于该PATH条目,请确保你按照之前的步骤作。
  2. 如果gcc输出正确但不正确gdb然后你需要安装MinGW-w64工具集中缺少的包。
    • 如果编译时你收到“MiDebuggerPath 的值无效”的提示,一个原因可能是你缺少了mingw-w64-gdb包裹。

创建一个Hello World应用

首先,让我们先搭建一个项目。

  1. 启动Windows命令提示符(在Windows搜索栏输入Windows命令提示符)。
  2. 执行以下命令。这些会创建一个空文件夹,称为projects你可以把所有VS Code项目放在那里。接下来的命令会创建并导航到一个叫做helloworld.从那里开始,你将打开helloworld直接在VS Code中。
mkdir projects
cd projects
mkdir helloworld
cd helloworld
code .

“code .”命令会在当前工作文件夹中打开VS Code,这个文件夹就成了你的“工作区”。通过选择“是,我信任作者”来接受工作空间信任对话框,因为这是你创建的文件夹。

在教程中,你会看到三个文件被创建在.vscode工作区中的文件夹:

  • tasks.json(建造说明)
  • launch.json(调试器设置)
  • c_cpp_properties.json(编译器路径和IntelliSense设置)

添加一个 Hello World 源代码文件

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

新建文件标题栏按钮

添加 hello world 源代码

现在粘贴这个源代码:

#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)中显示的样子:

文件资源管理器

你也可以启用自动保存,通过选择“文件 > 自动保存”来自动保存文件更改。你可以在 VS Code 用户界面文档中了解更多关于其他视图的信息。

注意:当你保存或打开C++文件时,可能会看到C/C++扩展发布的通知,告知Insiders版本的可用性,允许你测试新功能和修复。你可以选择X (清除通知)。

探索IntelliSense

IntelliSense 是一款通过添加代码编辑功能(如代码补全、参数信息、快速信息和成员列表)帮助你更快更高效地编写代码的工具。

想亲眼见证IntelliSense的实际应用, 悬停在上方vectorstring查看它们的类型信息。如果你打字msg.在第10行,你可以看到一个由IntelliSense生成的推荐成员函数的补全列表:

语句补全 IntelliSense

你可以按Tab键插入选中的成员。如果你加上开括号,IntelliSense 会显示需要哪些参数的信息。

如果 IntelliSense 尚未配置,打开命令面板(⇧⌘PWindows,Linux Ctrl+Shift+P),进入选择 IntelliSense 配置。从编译器下拉菜单中选择Use gcc.exe去配置。更多信息可见 IntelliSense 配置文档

快跑,helloworld.cpp

记住,C++扩展是利用你机器上安装的C++编译器来构建程序的。在尝试运行和调试之前,确保你已经完成了“安装 MinGW-w64 工具链”步骤helloworld.cpp在VS Code中。

  1. 开门helloworld.cpp所以它是活跃文件。

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

    helloworld.cpp播放按钮截图

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

    C++调试配置下拉菜单

你只有在第一次运行时才会被要求选择编译器helloworld.cpp.该编译器将被设置为“默认”编译器tasks.json档案。

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

    程序输出截图

恭喜你!你刚刚在VS Code中运行了你的第一个C++程序!

理解tasks.json

第一次运行程序时,C++扩展会生成一个tasks.json文件,你会在你的项目中找到.vscode文件夹。tasks.json存储你的构建配置。

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

{
  "tasks": [
    {
      "type": "cppbuild",
      "label": "C/C++: g++.exe build active file",
      "command": "C:\\msys64\\ucrt64\\bin\\g++.exe",
      "args": [
        "-fdiagnostics-color=always",
        "-g",
        "${file}",
        "-o",
        "${fileDirname}\\${fileBasenameNoExtension}.exe"
      ],
      "options": {
        "cwd": "${fileDirname}"
      },
      "problemMatcher": ["$gcc"],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "detail": "Task generated by Debugger."
    }
  ],
  "version": "2.0.0"
}

注意:你可以了解更多tasks.json变量引用中的变量。

command设置指定要运行的程序;在这种情况下,即g++.

argsarray 指定传递给 G++ 的命令行参数。这些参数按编译器预期的具体顺序列出。

该任务告诉 g++ 取活动文件(${file}编译,并生成输出文件(-o当前目录中的开关(${fileDirname}) 与活动文件同名,但.exe扩展(${fileBasenameNoExtension}.exe).对我们来说,这导致了helloworld.exe.

label价值是你在任务列表中看到的;你可以随意命名。

detail价值是你在任务列表中看到的任务描述。强烈建议重新命名该数值,以区别于类似任务。

problemMatcherValue 选择输出解析器用于在编译器输出中查找错误和警告。对于GCC,你用$gcc问题匹配器。

从现在起,播放按钮将从以下内容读取tasks.json想办法构建和运行你的程序。你可以在tasks.json,标记为默认的任务将由播放按钮使用。如果你需要更改默认编译器,可以在命令面板中运行“任务:配置默认构建任务”。或者你也可以修改tasks.json文件并通过替换该段来移除默认数据:

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

附带这个:

    "group": "build",

修改tasks.json

自2024年11月3日起,MSYS2已禁用对mingw-w64默认。这一变化影响了外卡的喜好"*.cpp"在构建命令中处理。要在你的tasks.json你必须明确列出文件,使用像这样的构建系统makecmake或者实施以下变通方法:https://www.msys2.org/docs/c/#expanding-wildcard-arguments。

如果你之前用过"${workspaceFolder}/*.cpp"编译所有.cpp当前文件夹中的文件,这个功能将不再直接生效。相反,你可以手动列出文件或定义构建脚本。

调试helloworld.cpp

要调试你的代码,

  1. 回到helloworld.cpp所以它是活跃文件。
  2. 通过点击编辑器边距或当前行的F9设置断点。《断点》截图 helloworld.cpp
  3. 在播放按钮旁的下拉菜单中,选择“调试 C/C++ 文件”。播放按钮下拉菜单截图
  4. 选择C/C++:从系统检测到的编译器列表中构建并调试活跃文件(只有在第一次运行或调试时才会被要求选择编译器)helloworld.cpp).C++调试配置下拉菜单

播放按钮有两种模式:运行 C/C++ 文件调试 C/C++ 文件。它会默认使用最后使用的模式。如果你在播放按钮中看到调试图标,只需选择播放按钮来调试,而不必使用下拉菜单。

探索调试器

在你开始逐步浏览代码之前,让我们花点时间注意用户界面的几处变化:

  • 集成终端出现在源代码编辑器底部。在调试控制台标签页中,你会看到显示调试器已启动运行的输出。

  • 编辑器会在启动调试器前高亮设置断点的那一行:

    初始断点

  • 左侧的运行和调试视图显示调试信息。你将在教程后面看到示例。

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

    调试控制

逐一了解代码

现在你准备好开始逐步解析代码了。

  1. 在调试控制面板中选择“Step Over”图标。

    踩踏按钮

    这将将程序执行推进到for循环的第一行,跳过所有内部函数调用vector以及stringmsg变量已被创建并初始化。注意左侧变量窗口的变化

    调试窗口

    在这种情况下,错误是预期的,因为虽然循环的变量名现在已被调试器看到,但该语句尚未执行,因此此时没有可读的内容。目录msg不过,这些都显现出来,因为该陈述已经完成。

  2. 再次按 Step,进入该程序的下一个语句(跳过所有执行的初始化循环代码)。现在,变量窗口显示了关于循环变量的信息。

  3. 再次按“Step”键执行cout陈述。(注意,C++ 扩展在循环结束前不会向调试控制台输出任何输出。)

  4. 如果你愿意,可以一直按“跨步”,直到向量中的所有单词都打印到控制台上。但如果你感兴趣,可以试试按“Step In”按钮,在C++标准库里逐步浏览源代码!

    回到你自己的代码,一种方法是一直按“Step over”。另一种方法是通过切换到helloworld.cpp在代码编辑器中,插入点放置在cout循环内的语句,并按下F9。左侧排水沟中会出现红点,表示该直线被设置了断点。

    主打断点

    然后按 F5 从标准库头部当前行开始执行。执行将继续cout.如果你愿意,可以再按一次F9来关闭断点。

    循环完成后,你可以在集成终端中看到输出,以及GDB输出的其他诊断信息。

    终端中的调试输出

定个手表

有时候你可能想在程序执行时跟踪变量的值。你可以通过在变量上设置一个手表来实现。

  1. 将插入点放置在环内。在“手表”窗口中,选择加号,在文本框中输入word,即循环变量的名称。现在,随着你穿过循环,查看“手表”窗口。

    手表窗口

  2. 在循环前添加以下陈述,再加一个手表:int i = 0;.然后,在循环内添加以下陈述:++i;.现在添加一个手表i就像你上一步做的那样。

  3. 要在断点暂停执行时快速查看任意变量的值,可以用鼠标指针悬停在断点上。

    鼠标悬停

用launch.json自定义调试

当你用播放键或F5调试时,C++扩展会动态生成调试配置。

有些情况下你需要自定义调试配置,比如指定运行时要传递给程序的参数。你可以在launch.json档案。

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

添加调试配置播放按钮菜单

然后你会看到一个下拉菜单,显示各种预定义的调试配置。选择 C/C++:g++.exe构建并调试活动文件

C++调试配置下拉菜单

VS Code 创建了launch.json文件.vscode文件夹“,看起来大致如下:

{
  "configurations": [
    {
      "name": "C/C++: g++.exe build and debug active file",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${fileDirname}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "C:\\msys64\\ucrt64\\bin\\gdb.exe",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "Set Disassembly Flavor to Intel",
          "text": "-gdb-set disassembly-flavor intel",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "C/C++: g++.exe build active file"
    }
  ],
  "version": "2.0.0"
}

在上述JSON中,program指定你想调试的程序。这里设置为当前文件文件夹(${fileDirname})以及带有.exe扩展(${fileBasenameNoExtension}.exe),如果helloworld.cpp是活跃文件,将为helloworld.exe.该args属性是运行时传递给程序的参数数组。

默认情况下,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++: Edit Configurations (UI) 来查看 C/C++ 配置界面。

命令调色板

这会打开 C/C++ 配置页面。当你在这里做更改时,VS Code 会把它们写入一个叫做c_cpp_properties.json.vscode文件夹。

这里,我们将配置名称改为 GCC,将编译器路径下拉菜单设置为 g++ 编译器,并将 IntelliSense 模式设置为与编译器匹配(gcc-x64)。

命令调色板

Visual Studio Code 将这些设置置于.vscode\c_cpp_properties.json.如果你直接打开那个文件,应该会看到这样的样子:

{
  "configurations": [
    {
      "name": "GCC",
      "includePath": ["${workspaceFolder}/**"],
      "defines": ["_DEBUG", "UNICODE", "_UNICODE"],
      "windowsSdkVersion": "10.0.22000.0",
      "compilerPath": "C:/msys64/mingw64/bin/g++.exe",
      "cStandard": "c17",
      "cppStandard": "c++17",
      "intelliSenseMode": "windows-gcc-x64"
    }
  ],
  "version": 4
}

只有当你的程序包含不在工作区或标准库路径中的头文件时,你才需要在包含路径数组设置中添加。强烈建议不要将系统包含路径添加到includePath为我们支持的编译器设置。

编译器路径

该扩展使用compilerPath设置以推断出 C++ 标准库头文件的路径。当扩展知道在哪里找到这些文件时,它可以提供智能完成和“前往定义”导航等功能。

C/C++ 扩展尝试填充compilerPath用基于系统中搜索的默认编译器。该扩展会在多个常见编译器位置查找,但只会自动选择位于“Program Files”文件夹或路径列在 PATH 环境变量中的某个。如果能找到 Microsoft Visual C++ 编译器,则会选择该编译器,否则会选择 gcc、g++ 或 clang 的某个版本。

如果你安装了多个编译器,可能需要更换compilerPath以匹配你项目中首选的编译器。你也可以在命令面板中使用 C/C++:选择 IntelliSense 配置......命令,选择扩展检测到的编译器之一。

故障排除

MSYS2已安装,但仍然找不到g++和gdb

您必须按照 MSYS2 官网的步骤作,使用 MSYS CLI 安装完整的 MinGW-w64 工具链(pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain),以及所有必修的先修课程。该工具链包含 g++ 和 gdb。

作为Windows用户,运行pacman命令会报错

Windows 机器上的 UCRT 仅包含在 Windows 10 及以后版本中。如果你使用的是其他版本的Windows,请执行以下不使用UCRT的命令:

pacman -S --needed base-devel mingw-w64-x86_64-toolchain

将 MinGW-w64 目的地文件夹添加到环境变量列表时,默认路径将是:C:\msys64\mingw64\bin.

MinGW 32位

如果你需要 MinGW 工具集的 32 位版本,请查阅 MSYS2 维基上的下载部分。它包含了指向32位和64位安装选项的链接。

下一步

  • 请查看VS Code用户指南
  • 请查看C++扩展概述。
  • 创建一个新工作区,复制你的工作区.vscode把JSON文件放进去,调整新工作区路径、程序名称等的必要设置,然后开始写代码!