C/C++环境配置

前言

本文力求以通俗的方式讲述环境配置。通俗不可避免地会不严谨——这也没法请各位批评指正(雾)。

本文描述的环境配置包含:

  1. 编辑器:用来编写和查看纯文本文件的软件,例如Windows自带的记事本。本文使用Visual Studio Code(简称VS Code)。

提示

注意:写字板、Word不属于纯文本编辑器,而应属于富文本编辑器,不在我们的讨论范围内。

  1. 编译器:将源代码翻译为可执行的二进制文件。本文使用GCC。广义上GCC是C、C++、Objective-C、Fortran、Ada、Go和D等多种语言的编译器(GNU Compiler Collection),狭义上GCC仅指C语言编译器(GNU C Compiler)。而本文所指的GCC介于两者之间:即C语言编译器和C++ 编译器。
  2. 调试器:单步执行、打断点等功能,调试程序。本文使用GDB。
  3. 语言服务器:通过语言服务器协议与编辑器交互,提供自动补全、静态分析与代码格式化等功能。本文使用clangd

安装

VS Code

前去VS Code官网下载并安装,只需要跟着安装程序的提示走就可以了。

提示

如果你确实需要高级选项,可以查看Running VS Code on Windows

MinGW-w64

前往mingw-builds-binariesGitHub Release页面,选择文件名中包含x86_64posixsehucrt的版本。截至本文发布,应该下载x86_64-14.2.0-release-posix-seh-ucrt-rt_v12-rev0.7z

信息

根据mingw-w64 threads: posix vs win32posix版本将使用posix API并允许使用std::threadwin32将使用win32 API,并禁用std::thread部分标准。

对于初学者而言,std::thread似乎是无关紧要的。

除了mingw-builds-binaries,也可以考虑谷雨构建的MinGW-w64,他只提供x86_64win32sehucrt。截至本文发布,应该下载gytx_x86_64-14.2.0-win32-seh-ucrt.7z

提示

这两个地址提供的文件均为7z格式。这是一种压缩包,如果你不知道用什么解压,请使用7-Zip

最新版本的Windows 11已经内置7z解压功能。

此后,将文件解压缩到一个合适的地方,不推荐解压到桌面或“下载”文件夹。要求路径中不包含中文与空格

打开解压缩得到的文件夹,在其中找到bin子文件夹。文件夹内应该是这样的:

Windows默认隐藏文件扩展名,所以也可能是这样的:

点击文件资源管理器的地址栏,将这一路径复制。接下来,打开Windows搜索(快捷键 Win + S),输入“环境变量”,点击“编辑系统环境变量”:

信息

我使用的是Windows 10系统。如果你使用Windows 11系统,那么Windows搜索的界面可能会不同。

打开之后,按如下步骤操作:

  1. 点击环境变量
  2. <你的用户名> 的用户变量下点击Path
  3. 点击编辑
  4. 点击新建
  5. 粘贴刚刚复制的路径;
      1. 三个确定

环境变量设置是否正确该如何检查呢?Win + R 打开“运行”,输入cmd并回车,打开命令行界面:

信息

我使用的是Windows终端(Windows Terminal)。你可能在这一步打开了Windows控制台主机(conhost),它应该是这个样子:

输入gcc --version并回车,如果环境变量配置正确,应当看到类似下面的输出:

而如果出现'gcc' 不是内部或外部命令,也不是可运行的程序或批处理文件。,则说明环境变量配置有问题,应当采取的措施包括但不限于:

  1. 重启Windows终端或Windows控制台主机。
  2. 重启电脑。
  3. 按照上述环境变量配置的步骤,再检查一遍。

clangd

前往clangd的GitHub Release页面,忽略掉“Pre-release”,选择“Latest”的windows版本。截至本文发布,应该下载clangd-windows-18.1.3.zip

这仍然是一个压缩包。与MinGW-w64类似,需要在解压缩后,将其中的bin文件夹添加到环境变量。

输入clangd --version并回车,如果环境变量配置正确,你应当看到类似下面的输出:

此外,也可以直接安装完整的LLVM,它包含了clangd。

配置

VS Code配置

插件安装

VS Code配置

Ctrl + Shift + P 打开VSCode的命令面板,输入“用户设置”,选择“首选项: 打开用户设置(JSON)”。

这时会自动打开settings.json,此即VS Code的配置文件,使用带注释的JSON语法(JSON with Comments)。在继续阅读之前,我假定你对这种文件格式有初步的了解。

加入配置项:

json
{
    "C_Cpp.intelliSenseEngine": "disabled"
}

关闭C/C++插件的自动补全(因为我们要用clangd)。

工作区

你需要用VS Code打开一个文件夹作为你的工作区。如果你是初学者,习惯于单文件编译/运行,那么我推荐你找一个恰当的位置新建文件夹。如果你正在进行一些项目,那项目文件夹就是你的工作区。

提示

有关工作区的更详细的信息,请参考VS Code文档:

工作区配置

为了正确地对单个C/C++源文件编译与调试,需要两个配置文件。

在工作区中新建.vscode文件夹,然后在其中新建launch.jsontasks.json

tasks.json

tasks.json是构建说明,指导C/C++插件怎样启动编译器。这里给出的是我自己使用的配置:

json
{
    "tasks": [
        {
            "type": "process",
            "label": "Compile-g++",
            "command": "g++",
            "args": [
                "-std=c++20",                 // 使用 C++ 20 标准
                "-g",                         // 生成调试信息
                "-m64",                       // 生成 64 位程序
                "-Wall",                      // 启用所有警告
                "-Wextra",                    // 启用额外警告
                "-fdiagnostics-color=always", // 输出彩色诊断信息
                "-o",
                "${fileDirname}\\${fileBasenameNoExtension}.exe",
                "${file}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
                "echo": false,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            },
            "detail": "Compiler: g++"
        }
    ],
    "version": "2.0.0"
}
launch.json

launch.json是调试说明,指导C/C++插件怎样启动调试器。这里给出的是我自己使用的配置:

json
{
    "configurations": [
        {
            "name": "g++",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "internalConsoleOptions": "neverOpen",
            "miDebuggerPath": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "Compile-g++"
        }
    ],
    "version": "2.0.0"
}

更复杂的配置可以参考Using GCC with MinGW

clangd配置

clang-format配置

clangd集成有clang-format,这是C/C++等语言的格式化工具。例如:

cpp
// 代码取自 https://github.com/Elkeid-me/csapp-3e-proxy-lab/blob/main/src/cache.cpp#L56
std::pair<std::shared_ptr<char[]>,std::size_t>cache::find_cache(const std::string&uri)
    { std::shared_lock
  lock(mtx);
  if (auto it{map.find(uri)};it!=map.end()){auto[ptr,size,_]{it->second};
it->second.stamp=++clock;
  return{ptr,size};
        } return {nullptr, 0};}
cpp
// 代码取自 https://github.com/Elkeid-me/csapp-3e-proxy-lab/blob/main/src/cache.cpp#L56
std::pair<std::shared_ptr<char[]>, std::size_t>
cache::find_cache(const std::string &uri)
{
    std::shared_lock lock(mtx);
    if (auto it{map.find(uri)}; it != map.end())
    {
        auto [ptr, size, _]{it->second};
        it->second.stamp = ++clock;
        return {ptr, size};
    }
    return {nullptr, 0};
}

为了使用clang-format,你需要在工作区根目录下有名为.clang-format的配置文件:

这个文件使用YAML语法。这里给出我使用的配置文件:

yaml
BasedOnStyle: LLVM
UseTab: Never
IndentWidth: 4
TabWidth: 4
BreakBeforeBraces: Allman
AllowShortIfStatementsOnASingleLine: false
IndentCaseLabels: false
ColumnLimit: 800
AccessModifierOffset: -4
NamespaceIndentation: All
FixNamespaceComments: false
IndentPPDirectives: AfterHash
PPIndentWidth: 1

详细说明请见官方文档Clang-Format Style Options。你可以自行调配符合你口味的代码风格。

clangd

终于到了最复杂的部分——clangd本体的配置。对于初学者(单文件编译),请看.clangd;如果你正在使用某种构建工具,请看compile_commands.json

.clangd

.clangd记录了你在编译文件时使用的编译器、编译参数等。.clangd在工作区根目录下——换句话说,它应该跟.clang-format在一起。

这个文件使用YAML语法。这里给出我使用的配置文件:

yaml
CompileFlags:
  Compiler: g++
  Add: [-std=c++20, -m64, -Wall, -Wextra, --target=x86_64-w64-windows-gnu]

详细说明请见官方文档Configuration

compile_commands.json

compile_commands.json是一个JSON文件,指定项目中每个源代码编译的方式。典型的compile_commands.json如下:

compile_commands.json可以人工编写,但更推荐的方式是用工具自动生成。请选择你的构建工具:

提示

如果你不明白什么是构建工具,那么很显然,你应该使用.clangd

详细信息见Project setup

CMake

在运行CMake时加入参数-DCMAKE_EXPORT_COMPILE_COMMANDS=1

也可以在CMakeLists.txt中加入:

cmake
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

如果compile_commands.json被生成在项目根目录,或项目根目录/build,clangd可以自动识别。否则,你需要手工移动compile_commands.json到项目根目录。

只有在生成Makefile或Ninja时,CMake才会生成compile_commands.json

Xmake

Xmake是一个基于Lua的轻量级跨平台构建工具。

要使用Xmake生成compile_commands.json,可以直接运行:

console
xmake project -k compile_commands

也可以在xmake.lua中加入:

lua
add_rules("plugin.compile_commands.autoupdate")

来自动更新compile_commands.json

GNU make

GNU make无法自动生成compile_commands.json。不过嘛,有一个网站Generate Compilation Database from GNU make output online可以根据make的输出生成compile_commands.json。具体来说,你需要:

  1. 确保make输出的是英文。对于Ubuntu,可能需要运行
    console
    LANG=en_US.UTF-8
  2. 运行
    console
    make -nw
  3. 将2.的输出粘贴到上述网站。点击Generate!即可获得compile_commands.json

此外,clangd官方推荐使用Bear为基于make或其他构建工具的项目生成compile_commands.json

Todo List
Valaxy v0.28.4 驱动|主题-Yunv0.28.4