首发于 VS Code
[万字长文]Visual Studio Code 配置 C/C++ 开发环境的最佳实践(VSCode + Clangd + XMake)

[万字长文]Visual Studio Code 配置 C/C++ 开发环境的最佳实践(VSCode + Clangd + XMake)

本文持续更新,建议收藏

0 前言

听说 C++ 23 中 std::printf 又要王者归来,如果不想学 C艹,那试试 Rust 也不错:

为什么要写这篇文章?

自从微软推出了 LSP 语言服务协议(Language Server Protocol) 后,每种编程语言只需实现一个强大的 Language Server 后端,就可以为任何支持 LSP 协议的 IDE/Editor 前端提供代码高亮、自动补全、导航重构等功能,而不必为每一个开发工具单独开发插件。实际上,正是 LSP 和 DAP 的出现让 IDE 和编辑器的界限越来越模糊。

截止到 2022 年,开源社区已经涌现出一大批优秀的 Language Server 实现,它们在各自领域已经拥有了接近甚至超越商业化 IDE 的功能:

关于更多 Language Server 实现:

目前支持 LSP 协议的 IDE/Editor:

  • Visual Studio Code
  • Neovim
  • Sublime Text
  • Emacs
  • Fleet
  • Eclipse
  • ...

其中 VS Code 是当下最流行的代码编辑器,拥有现代化的外观和丰富的插件生态,配合 LSP 就是一个轻量级的 IDE。但笔者在配置开发环境时发现,互联网上大量教程要么已经过时、要么使用的插件和工具链并不理想,给人一种 VSC 仍不堪大用的感觉。实际上,对于 Rust、Haskell 等编程语言,VS Code 未必比 Jetbrains 全家桶逊色。

C/C++ 因其复杂的语法、沉重的历史包袱、多样的平台和工具链,导致 IDE/Editor 对工程项目的支持往往不甚理想。本文将初步介绍如何利用 XMake 在 Windows、Macos、Linux 平台配置 VSCode C/C++ 开发环境。

VSCode 官方文档配置 相比拥有的优势

  • Clangd 具有更优秀的性能,微软官方 Cpptools 的代码提示功能有明显延迟
  • Clangd 提供更精准的「功能」、「转到定义」、「重命名符号」、「自动添加头文件」等功能(大名鼎鼎的 CLion 就是基于 Clangd)
  • Clang-Tidy 提供了强大的「静态检查」支持,并对于部分代码提供「快速修复」功能。详情请见 Clang-Tidy Checks。本文主要添加了对于「Google 开源项目风格指南」「Cpp Core Guidelines」和性能、潜在的 bug、移植性、现代 C++ 的检查
  • 微软官方 Cpptools 仅提供 Debug 功能(也支持使用 CodeLLDB 插件进行调试)
  • 使用 XMake 而非 CMake 作为项目构建工具 。XMake 是一个基于 Lua 的轻量级跨平台自动构建工具,适用于多种编程语言,关于 XMake 相对 CMake 的优势,知乎上有大把的文章。XMake 插件可以轻松一键编译、运行和调试, 无需配置 tasks.json launch.json ,会给你一种在 C++ 中用 Cargo 的错觉(ㄟ( ▔, ▔ )ㄏ

笔者手头没有 Mac,新电脑又装不了黑苹果,所以配置过程中如果遇到问题,请善用互联网:

  • 项目官网
  • GitHub issue
  • 知乎
  • CSDN
  • Stack Overflow
  • 搜索引擎
  • ...

还是无法解决的话,欢迎在评论区提出,大家一起讨论。

1 安装开发工具

首先在操作系统上安装 C/C++ 工具链(编译器和构建工具)

Windows

Windows 平台最常用的 C/C++ 编译器是微软的 MSVC,这也是目前对 C++20 标准支持最好的编译器。最简单的安装方法就是装一个 Community Visual Studio 2022 ,然后在如下对话框中选择“使用 C++ 的桌面开发”(其它工具如 git 也可以在这里安装)

如果你已经安装了 Visual Studio 2022,直接打开 Visual Studio Installer,然后点击修改

你也可以安装 C + + 桌面开发工具包,而无需安装完整的 Visual Studio。从 Visual Studio 下载页 向下滚动,直到在“所有下载”部分中看到“ 适用于 Visual Studio 2022 的工具”,然后点击“为 Visual Studio 2022 生成工具”的下载按钮。这将启动 Visual Studio Installer,它将打开一个对话框,显示可用的 Visual Studio Build Tools,后安装即可:

为 MSVC 编译器配置环境变量( 这一步应该是可选的,配置的时候不妨先跳过去,遇到问题再回来 ):

首先打开 设置-系统-关于界面,点击 Advanced system settings,在弹出窗口中点击 Environment Variables(如下图所示):

然后在弹出的窗口中,在 User variables for XXX 一栏中,配置用户变量(如下图所示):

接下来 要配置的路径会因你的系统环境而有所不同!请在你的文件管理器地址栏中复制对应的路径

点击 New 按钮,新建几个用户变量,变量名和变量值如下表:

Variable Value
MSVC C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.33.31629
WK10_BIN C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0
WK10_INCLUDE C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0
WK10_LIB C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0
INCLUDE %WK10_INCLUDE%\ucrt;%WK10_INCLUDE%\um;%WK10_INCLUDE%\shared;%MSVC%\include;
LIB %WK10_LIB%\um\x64;%WK10_LIB%\ucrt\x64;%MSVC%\lib\x64;

然后在选则名为 Path 的用户变量,点击 Edit,点击 New 新增如下三行内容:

%MSVC%\bin\HostX64\x64 
%WK10_BIN%\x64
C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin

最后在 WIndows 终端中输入 cl 命令和 cmake 命令进行验证(如下图所示):

本教程无需使用 cmake,但以防万一,还是配置好环境变量

然后安装 XMake:

可以在 Github Release 下载并安装最新版的 XMake:

点击 xmake-master.win64.exe 即可下载安装包

也可以通过 Powershell 脚本安装 XMake:

$ Invoke-Expression (Invoke-Webrequest 'https://xmake.io/psget.text' -UseBasicParsing).Content

MacOS X

OS X 平台使用 Clang-LLVM 工具链进行 C/C++ 开发,之前提到的 Clangd 就是 LLVM 工具链的一个子项目。如果你安装过 XCode ,应该会附带 Apple Clang 编译器。通过以下命令检验 Clang 是否安装:

$ clang --version

如果无法输出版本信息,通过以下命令安装 Apple Calng:

$ xcode-select --install

然后通过 MacOS 上著名的包管理工具 Homebrew 安装 XMake:

$ brew install xmake

如果你的 Mac 上没有安装 Homebrew,因为 homebrew官网 给出的安装脚本需要科学上网,笔者建议用国内 某大神写的安装脚本 ,不仅免去科学上网的繁琐,安装完成后还会自动转换为国内镜像源,在系统终端内输入如下命令以安装 Homebrew:

$ /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

按照说明进行操作:

安装过程出现错误请查询:

相比 XCode 自带的 Apple Calng,通过 Homebrew 安装的 Clang 对 C++20 标准支持更好,各大编译器对 C++ 版本(语言特性和标准库)的支持见:

所以你也可以用 Homebrew 安装 Clang-LLVM:

$ brew install llvm

输入以下命令添加环境变量:

$ echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc
$ echo 'export LDFLAGS="-L/usr/local/opt/llvm/lib"' >> ~/.zshrc
$ echo 'export CPPFLAGS="-I/usr/local/opt/llvm/include"' >> ~/.zshrc

可能需要输入 Password,注意输入密码时终端不会显示已输入的字符(你的键盘没有坏~)

在终端内键入命令,以验证是否安装成功:

$ which clang
$ which clangd 
$ which lldb 

会输出对应的安装路径。

GNU/Linux

可以使用 GCC 编译器,也可以通过系统的包管理器安装 Clang-LLVM 工具链,用 GNU/Linux 工作的大佬应该懂得取舍。

推荐使用 shell 脚本安装 XMake:

$ bash <(wget https://xmake.io/shget.text -O -)

2 配置 VSCode 及其拓展

VSC 快捷键

  • Ctrl+鼠标左键​ 是文件、函数等跳转。
  • Alt + ← 跳转后返回原处
  • Ctrl + Shift + O 列出函数名
  • Ctrl + P ​ 列出近期打开的文件名
  • Ctrl + Tab ​ 列出最近打开的文件,在开发时,两个文件间切换时效率很高。

插件推荐

官网 安装 Visual Studio Code 后,安装如下拓展:

  • clangd (安装后建议通过它下载 clangd 二进制包)
  • C/C++ (又名 cpptools,用来 debug 程序)
  • XMake (XMake 插件)
  • C++ Class Creator (快速创建 C++ Class)
  • One Dark Pro
  • Gruvbox Material Icon Theme (图标主题)
  • Project Manager(收藏、识别和管理你的工作空间和项目文件夹)
  • Error Lens(更直观的错误提示,可选)
  • Vim(Vim 模拟器,不了解 Vim 的不要安装)
  • GitLens(Git插件,可选)
  • Git Graph(Git插件,可选)
  • GitHub Copilot(Github 开发的代码智能提示插件,不建议初学者使用)
注意: 「C/C++」插件和「clangd」插件共存,VSC 会提示发生冲突,请选择「Disable IntelliSense」

Vim 插件的使用:

settings.json 配置 ⚠

通过 F1 ctrl/command+shift+p 快捷键打开 VSC 的命令面板(Command Palette),然后输入并执行 Preferences: Open User Settings (JSON) 即可打开名为 setting.json 的设置文件。笔者倾向于将尽可能多的设置放在 settings.json 中,以便于用账号进行同步。下面贴出笔者的个人配置及说明,你可以 有选择地粘贴 到自己的 settings.json 中。

  • 请认真读一遍注释!
  • 除全局 settings.json 外,这些配置也可以粘贴到项目文件夹中的 .vscode/settings.json 中,这样只对该项目生效,且优先级高于全局设置
  • 如果你认为 Clangd 插件对 C++20 语法的支持还不够好,也可以使用 cpptools
{
    // [[Terminal]]
    "terminal.integrated.defaultProfile.osx": "zsh", // MacOS: 集成终端默认为 zsh
    "terminal.integrated.macOptionIsMeta": true, // MacOS:  Option 键视为终端上的元键
    "terminal.integrated.tabs.showActions": "always", // 始终显示“新建终端”按钮旁的“终端拆分”和“终止”按钮
    "terminal.integrated.tabs.showActiveTerminal": "always", // 始终显示活动终端
    "terminal.integrated.enableBell": true, // 集成终端启用视觉化铃声
    "terminal.integrated.gpuAcceleration": "on", // 集成终端使用GPU加速
    "terminal.integrated.rightClickBehavior": "selectWord", // 集成终端右击时选择光标下方的字词,并打开上下文菜单
    "terminal.integrated.defaultProfile.windows": "PowerShell",
    "terminal.integrated.env.windows": {
        "LC_ALL": "zh_CN.UTF-8" // 集成终端编码: zh_CN.UTF-8
    "terminal.integrated.profiles.windows": {
        "PowerShell": {
            "source": "PowerShell",
            "icon": "terminal-powershell"
        "Command Prompt": {
            "path": [
                "${env:windir}\\Sysnative\\cmd.exe",
                "${env:windir}\\System32\\cmd.exe"
            "args": [],
            "icon": "terminal-cmd"
        "Git Bash": {
            "source": "Git Bash"
        "Windows PowerShell": {
            "path": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
    // [[Git]]
    "git.autofetch": true, // 自动从当前 Git 存储库的默认远程库提取提交
    "git.confirmSync": false, // 同步 Git 存储库前确认
    "git.enableSmartCommit": true, // 没有暂存的更改时,直接提交全部更改
    "git.mergeEditor": true, // 启用三向合并编辑器
    "gitlens.defaultDateLocale": null,
    "gitlens.defaultDateFormat": null,
    "gitlens.defaultDateShortFormat": null,
    // [[Vim]]
    "vim.easymotion": true,
    "vim.incsearch": true,
    "vim.useSystemClipboard": true,
    "vim.useCtrlKeys": true,
    "vim.hlsearch": true,
    "vim.insertModeKeyBindings": [
            "before": [
                "j",
            "after": [
                "<Esc>"
    "vim.normalModeKeyBindingsNonRecursive": [
            "before": [
                "<leader>",
            "after": [
                "d",
            "before": [
                "<C-n>"
            "commands": [
                ":nohl"
            "before": [
            "commands": [
                "lineBreakInsert"
            "silent": true
    "vim.leader": "<space>",
    "vim.handleKeys": {
        "<C-a>": false,
        "<C-f>": false
    // [[Appearance]]
    "terminal.integrated.fontSize": 14, // 集成终端字号
    "explorer.compactFolders": false, // 资源管理器不采用紧凑模式
    "editor.fontFamily": "JetBrains Mono Medium, LXGW Bright Medium", // 编辑器全局字体
    "editor.fontLigatures": true, // 启用连字体
    "editor.fontSize": 14, // 字号
    // "editor.fontWeight": "450", // 字体粗细
    "editor.lineHeight": 0, // 行高:使用 0 根据字号自动计算行高
    "editor.bracketPairColorization.enabled": true, // 控制是否对括号着色
    "editor.bracketPairColorization.independentColorPoolPerBracketType": false, // 各类括号着色等级不独立
    "editor.guides.bracketPairs": true, // 启用括号指导线
    "editor.guides.bracketPairsHorizontal": "active", // 启用水平括号指导线
    "editor.guides.highlightActiveIndentation": false, // 禁用高亮选中的缩进指导线
    "editor.guides.indentation": false, // 禁用缩进指导线
    "editor.semanticHighlighting.enabled": true, // 启用语义高亮
    // 自定义语法高亮示例
    "editor.semanticTokenColorCustomizations": {
        "[One Dark Pro]": {
            "rules": {
                // "selfKeyword": {
                    // "foreground": "#DD94E5",
                    // "fontStyle": "italic"
                // }
    "workbench.colorTheme": "One Dark Pro", // 颜色主题
    "workbench.iconTheme": "gruvbox-material-icon-theme", // 图标主题
    "workbench.startupEditor": "none", // 在没有从上一个会话恢复出信息的情况下,在启动时不打开编辑器
    "workbench.view.alwaysShowHeaderActions": true, // 显示视图头部的操作项
    // 括号颜色
    "workbench.colorCustomizations": {
        "[One Dark Pro]": {
            "editorBracketHighlight.foreground3": "#9CDCFE",
            "editorBracketHighlight.foreground4": "#F3FD00",
            "editorBracketHighlight.foreground5": "#F47D9F",
            "editorBracketHighlight.foreground6": "#A5ADFE"
    // 针对输出窗口的部分设置
    "[plaintext]": {
        "editor.fontLigatures": false, // 不使用连字体
        "editor.formatOnSave": false, // 不在保存时自动格式化
        "editor.wordWrap": "on" // 启用自动换行
    // [[Copilot]]
    "github.copilot.enable": {
        "*": true,
        "yaml": false,
        "plaintext": true,
        "markdown": false,
        "jsonc": false,
        "cpp": false
    // [[XMake]]
    "xmake.runMode": "buildRun", // 运行前自动 build
    //




    
 "xmake.additionalConfigArguments": "--cc=clang-cl --cxx=clang-cl", // windows 可以指定 clang-cl 作为编译器
    // "xmake.debugConfigType": "codelldb", // 使用 codelldb 插件而非 cpptools 进行调试
    "xmake.buildLevel": "verbose", // 设置编译时输出信息级别,默认是warnings级别,仅输出编译警告信息以及正常信息,verbose级别输出完整的编译命令行参数,debug级别对应 xmake -vD 的诊断信息,会打印出错的栈信息
    "xmake.customDebugConfig": {
        "console": "integratedTerminal" // XMake调试时使用集成终端而非 debug console,也可以使用 externalTerminal
    "xmake.debuggingTargetsArguments": {
        "default": [
            // 啥也没有
    // [[C/C++]]
    // cpptools
    "C_Cpp.intelliSenseEngine": "Disabled", // 禁用微软 Cpptools 插件的提示功能
    "C_Cpp.codeAnalysis.runAutomatically": false,
    "C_Cpp.formatting": "Disabled",
    // clangd
    "clangd.path": "c:\\Users\\Sirius\\AppData\\Roaming\\Code\\User\\globalStorage\\llvm-vs-code-extensions.vscode-clangd\\install\\15.0.3\\clangd_15.0.3\\bin\\clangd.exe", // clangd 安装路径
    // Clangd 运行参数(在终端/命令行输入 clangd --help-list-hidden 可查看更多)
    "clangd.arguments": [
        "--all-scopes-completion", // 全局补全(补全建议会给出在当前作用域不可见的索引,插入后自动补充作用域标识符),例如在main()中直接写cout,即使没有`#include <iostream>`,也会给出`std::cout`的建议,配合"--header-insertion=iwyu",还可自动插入缺失的头文件
        "--background-index", // 后台分析并保存索引文件
        "--clang-tidy", // 启用 Clang-Tidy 以提供「静态检查」,下面设置 clang tidy 规则
        "--clang-tidy-checks=performance-*, bugprone-*, misc-*, google-*, modernize-*, readability-*, portability-*",
        "--compile-commands-dir=${workspaceFolder}/.vscode", // 编译数据库(例如 compile_commands.json 文件)的目录位置
        "--completion-parse=auto", //  clangd 准备就绪时,用它来分析建议
        "--completion-style=detailed", // 建议风格:打包(重载函数只会给出一个建议);还可以设置为 detailed
        // "--query-driver=/usr/bin/clang++", // MacOS 上需要设定 clang 编译器的路径,homebrew 安装的clang  /usr/local/opt/llvm/bin/clang++
        // 启用配置文件(YAML格式)项目配置文件是在项目文件夹里的“.clangd”,用户配置文件是“clangd/config.yaml”,该文件来自:Windows: %USERPROFILE%\AppData\Local || MacOS: ~/Library/Preferences/ || Others: $XDG_CONFIG_HOME, usually ~/.config
        "--enable-config",
        "--fallback-style=Webkit", // 默认格式化风格: 在没找到 .clang-format 文件时采用,可用的有 LLVM, Google, Chromium, Mozilla, Webkit, Microsoft, GNU
        "--function-arg-placeholders=true", // 补全函数时,将会给参数提供占位符,键入后按 Tab 可以切换到下一占位符,乃至函数末
        "--header-insertion-decorators", // 输入建议中,已包含头文件的项与还未包含头文件的项会以圆点加以区分
        "--header-insertion=iwyu", // 插入建议时自动引入头文件 iwyu
        "--include-cleaner-stdlib", // 为标准库头文件启用清理功能(不成熟!!!)
        "--log=verbose", //  Clangd 生成更详细的日志
        "--pch-storage=memory", // pch 优化的位置(Memory  Disk,前者会增加内存开销,但会提升性能)
        "--pretty", // 输出的 JSON 文件更美观
        "--ranking-model=decision_forest", // 建议的排序方案:hueristics (启发式), decision_forest (决策树)
        "-j=12" // 同时开启的任务数量
    // Clangd 找不到编译数据库(例如 compile_flags.json 文件)时采用的设置,缺陷是不能直接索引同一项目的不同文件,只能分析系统头文件、当前文件和include的文件
    "clangd.fallbackFlags": [
        "-pedantic",
        "-Wall",
        "-Wextra",
        "-Wcast-align",
        "-Wdouble-promotion",
        "-Wformat=2",
        "-Wimplicit-fallthrough",
        "-Wmisleading-indentation",
        "-Wnon-virtual-dtor",
        "-Wnull-dereference",
        "-Wold-style-cast",
        "-Woverloaded-virtual",
        "-Wpedantic",
        "-Wshadow",
        "-Wunused",
        "-pthread",
        "-fuse-ld=lld",
        "-fsanitize=address",
        "-fsanitize=undefined",
        "-stdlib=libc++",
        "-std=c++20"
    "clangd.checkUpdates": true, // 自动检测 clangd 更新
    "clangd.onConfigChanged": "restart", // 重启 clangd 时重载配置,具体方法: F1 + Fn 打开命令面板,然后搜索“clangd: restart"
    "clangd.serverCompletionRanking": true, // 借助网上的信息排序建议
    "clangd.detectExtensionConflicts": true, // 当其它拓展与 clangd 冲突时警告并建议禁用
    "editor.suggest.snippetsPreventQuickSuggestions": false, // clangd的snippets有很多的跳转点,不用这个就必须手动触发Intellisense了
    // [[LLDB]]
    "lldb.commandCompletions": true, // LLDB 指令自动补全
    "lldb.dereferencePointers": true, // LLDB 指针显示解引用内容
    "lldb.evaluateForHovers": true, // LLDB 鼠标悬停在变量上时预览变量值
    "lldb.launch.expressions": "native", // LLDB 监视表达式的默认类型
    "lldb.showDisassembly": "never", // LLDB 不显示汇编代码
    "lldb.verboseLogging": true, // LLDB 生成更详细的日志
    // [[General Settings]]
    "breadcrumbs.filePath": "on", // 控制是否及如何在“导航路径”视图中显示文件路径
    // debug
    "debug.console.acceptSuggestionOnEnter": "on", // 调试控制台中可以用 enter 接受建议
    "debug.internalConsoleOptions": "neverOpen", // 从不自动打开内部调试控制台
    // editor
    "editor.acceptSuggestionOnEnter": "on", // 编辑器中可以用 enter 接受建议
    "editor.stickyScroll.enabled": true, // 启用粘滞滚动,即显示上一级对应的代码
    "editor.wordBasedSuggestionsMode": "allDocuments", // 建议所有打开文档中的字词
    "editor.unicodeHighlight.ambiguousCharacters": false, // 不突出显示可能与基本 ASCII 字符混淆的字符
    "editor.inlayHints.enabled": "on", // 在编辑器中显示内联提示
    "editor.minimap.enabled": true, // 控制是否显示缩略图cod
    "editor.formatOnType": true, // 自动格式化
    "editor.renderWhitespace": "none", // 控制编辑器在空白字符上显示符号的方式
    "editor.snippetSuggestions": "top", // 代码片段建议置于其他建议之上
    "editor.stickyTabStops": true, // 使用空格缩进时模拟制表符的行为,可以方便对齐
    "editor.tabSize": 4, // 一个制表符 = 4个空格
    "editor.suggest.insertMode": "replace", // 建议的接受方式
    "editor.suggest.localityBonus": true, // 控制排序时是否提高靠近光标的词语的优先级
    "editor.suggest.matchOnWordStartOnly": false, // 禁用建议必须匹配开头
    "editor.suggest.shareSuggestSelections": true,
    "editor.suggest.showStatusBar": true, // 控制建议小部件底部的状态栏可见
    "editor.suggestOnTriggerCharacters": true, // 控制在键入触发字符后是否自动显示建议
    "editor.suggestSelection": "first", // 始终预先选择第一个建议
    "editor.wordBasedSuggestions": true, // 控制是否根据文档中的文字提供建议列表
    "editor.autoClosingOvertype": "always", // 控制编辑器应当自动改写左引号或右引号
    "editor.detectIndentation": false, // 禁用自动检测文件缩进模式和缩进大小,即打开文件后自动将文件更改为 VSCode 配置的缩进格式
    "editor.formatOnSave": true, // 保存自动格式化代码
    "editor.formatOnPaste": true, // 粘贴自动格式化
    "editor.quickSuggestionsDelay": 0, // 控制显示快速建议前的等待时间(毫秒)
    "editor.inlineSuggest.enabled": true, // 在编辑器中自动显示内联建议
    "editor.parameterHints.enabled": true, // 是否在输入时显示含有参数文档和类型信息的小面板
    // 控制是否在键入代码时自动显示建议
    "editor.quickSuggestions": {
        "comments": false, // 键入注释时不允许
        "other": true, // 键入其他时允许
        "strings": false // 键入字符串时不允许
    // explorer
    "explorer.confirmDragAndDrop": false, // 移动文件时无需确认
    "explorer.confirmDelete": true, // 删除文件确认
    "explorer.incrementalNaming": "smart", // 粘贴同名文件时的重命名方式;smart: 在重复名称末尾智能地添加/递增数字
    // files
    "files.autoSave": "afterDelay", // 自动保存
    "files.hotExit": "onExitAndWindowClose", // 在会话间记住未保存的文件,允许在退出编辑器时跳过保存提示 onExitAndWindowClose: 退出或窗口关闭时
    // 配置排除的文件和文件夹的glob模式,文件资源管理器将根据此设置决定要显示或隐藏的文件和文件夹
    "files.exclude": {
        "**/.classpath": true,
        "**/.factorypath": true,
        "**/.project




    
": true,
        "**/.settings": true
    "files.associations": {
        "*.pl": "prolog"
    // notebook
    "notebook.lineNumbers": "on", // 控制单元格编辑器中行号的显示
    // 应该在何处显示单元格工具栏,或是否隐藏它
    "notebook.cellToolbarLocation": {
        "default": "right", // 默认: 右边
        "jupyter-notebook": "left" // jupyter-notebook: 左边
    // search
    "search.showLineNumbers": true, // 显示搜索结果所在行号
    "search.smartCase": true, // 当搜索词为小写时,则不区分大小写进行搜索,否则区分大小写
    // 配置在搜索中排除的文件和文件夹的glob模式
    "search.exclude": {
        // "someFolder/": true,
        // "somefile": true
    // workbench
    "workbench.settings.editor": "json", // 默认打开 settings.json 进行设置
    "workbench.editor.historyBasedLanguageDetection": true, // 允许语言检测使用编辑器历史记录
    // window
    "window.restoreWindows": "all",
    "window.titleBarStyle": "native",
    "window.menuBarVisibility": "hidden",
    // output
    "output.smartScroll.enabled": true, // 输出窗口智能滚动:点击时锁定,点击最后一行时解锁
    // problems
    "problems.showCurrentInStatus": true, // 在状态栏显示当前问题
    "problems.sortOrder": "position", // 控制问题导航的显示顺序
    // other
    "security.workspace.trust.untrustedFiles": "open",
    "extensions.ignoreRecommendations": true,
    "http.proxySupport": "on",
    "[log]": {
        "editor.fontSize": 16
    "grunt.autoDetect": "on", // Grunt 任务自动检测
    "gulp.autoDetect": "on" // Gulp 任务自动检测
}

根据 Clangd 官方文档 ,Clangd 配置文件采用 YAML 格式,包括用户配置(全局配置)和项目配置。项目配置在位于该项目文件夹根目录的 .clangd 文件中,用户配置在如下路径的 clangd/config.yaml 文件中。

  • Windows: %USERPROFILE%\AppData\Local
  • MacOS X: ~/Library/Preferences/
  • Others: $XDG_CONFIG_HOME,通常是 ~/.config

通常情况下系统中并无此文件,可以按 F1 打开 VSCode 命令面板,输入 clangd: Open user configuration file ,即可创建并打开 config.yaml 文件,然后编辑文件内容如下以发挥 Clangd 的全部特性(项目配置同理):

Diagnostics:
  ClangTidy:
    Add: ["*"]
    Remove:
        abseil*,
        fuchsia*,
        llvmlib*,
        zircon*,
        altera*,
        google-readability-todo,
        readability-braces-around-statements,
        hicpp-braces-around-statements,
        modernize-use-trailing-return-type,
Index:
  Background: Build

除了 settings.json 设置外,还可为每个项目设置 clangd tidy 规则,用于静态分析提示。只需在项目文件夹下建立 .clang-tidy 文件,文件具体内容请参考 clangd 官方文档。

3 VSCode 使用 XMake 构建系统管理 C/C++ 项目

本文旨在简单介绍 VSCode 和 XMake 的配合使用,因此不会深入讲解 XMake。关于 XMake 的使用,请参考教程和官网:

首先检查 XMake 是否安装,运行

$ xmake --help

能正常输出则说明安装成功。

使用 shell 脚本安装的 XMake 已经带有自动补全和虚拟环境功能。对于其他方式安装的 XMake,如果想要启用自动补全和虚拟环境功能,需要在安装完毕后运行

$ xmake update --integrate

安装之后,若要将xmake更新至最新版,只需使用

$ xmake update

命令行中的 XMake

使用 shell 切换至一个有足够权限的文件目录,创建 helloworld 项目:

$ xmake create helloworld
$ cd helloworld

如果已经安装了 C/C++ 的编译器(GCC/XCode/Visual Studio 等),那么可以直接在 Shell 中编译并运行该项目:

$ xmake # 编译
$ xmake run helloworld # 运行
Hello World!

VSCode 中的 XMake

除了通过命令行新建 XMake 项目,也可以用 xmake-vscode 插件提供的工程创建功能来完成 C/C++ 工程的创建:首先新建一个空工程目录,用 VSC 打开它,然后打开命令面板,输入 xmake: CreateProject 命令,会提示找不到 xmake.lua 配置文件的错误,如图:

点击 Create a new xmake project 按钮,选择项目语言(这里选择 C++)

选择 console 类型的工程

完成后,项目就创建好了,工程根目录下有 xmake.lua 配置文件。Clangd 需要读取 C/C++ 项目的编译数据库(通常是 compile_commands.json 文件)才能发挥全部功能,这里 VSC 插件自动地在 .vscode 文件夹中帮你生成该文件。

我们也可以先在终端运行 xmake config 完成 configure 过程,然后在控制面板中输入 XMake: UpdateIntellsense ,就可以在 .vscode 文件夹中找到自动生成的 compile_commands.json 。此后,如果你的项目构建过程发生变化,重复上述步骤:运行 xmake config 命令后打开控制面板输入 XMake: UpdateIntellisense 即可。

在 VSCode 下方的 Status Bar 中,有一排与 XMake 有关的操作按钮:

  • 项目根目录
  • 项目构建平台
  • 项目构建架构
  • 构建模式(debug or release)
  • 构建工具链(例如在 Windows 上选择 MSVC)
  • 一键构建项目
  • 目标程序
  • 一键运行项目 (笔者设置了运行前自动构建)
  • 一键调试项目 (调试前用 debug 模式构建)
  • 宏记录
  • 宏回放
  • ...
注意:release 模式构建的目标程序,不附带调试符号信息。因此必须用 debug 模式构建 ,使其带上调试符号信息后,才能进行调试。

不仅仅是创建工程,在安装 xmake-vscode 插件后,使用 vscode 打开一个根目录带有 xmake.lua 的工程,那 vscode 底部的 xmake 工具栏面板也会自动激活。除命令行和 VSC 底部的 XMake 工具栏按钮外, 更多功能可以在命令面板(Command Palette)中输入 xmake 使用 ,例如底部工具链只有 Build 按钮而没有 rebuild ,但你可以在命令面板找到该功能。

编译完成后,如果想要清理生成的文件,可以运行 xmake clean 来清理中间文件与目标文件。 xmake clean -a 可以连同 XMake 缓存一同清除。 xmake config -c 命令仅仅清除 XMake 缓存并重新生成,不清理中间文件和目标文件。

Tips: XMake 文件发生更改后,为提升效率默认原来的缓存继续生效,可能会影响构建过程。建议在项目文件发生较大更改后,或者遇到问题的时候手动运行 xmake f -c 来清理缓存。

xmake.lua 配置文件

XMake 工程的配置文件是根目录里的 xmake.lua,在文件中添加 set_languages 语句设置语言版本,这一条语句通常放在所有 target 声明之前,全局生效,否则容易导致标准库冲突。举个栗子,你希望 Clangd 和编译器使用 C99 和 C++20 标准,只需在 xmake.lua 中增加 set_languages("c99", "c++20") 这样一行配置即可(如下图所示,你可以在一个项目里同时设置 C 和 C++ 的标准),xmake 会自动根据你对 xmake.lua 的更改生成新的 compile_commands.json 文件,Clangd 进行自动补全、静态检查依据的标准也会随之改变。

编辑 xmake.lua 文件时 xmake-vscode 插件具备自动提示和补全支持,只需要输入 add_ set_ 等字样的文本,就会自动列举出与其相关的所有 API 供我们使用,来方便快速配置 xmake.lua。

代码格式化

VScode 快捷键 Alt + Shift + F 格式化代码,如果你对之前设置中几种代码格式化样式都不满意,在 VSCode 打开的项目根目录中添加 .clang-format 文件,编辑该文件内容即可自定义 Format 样式,该文件模板如下:

# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto
Language: Cpp
# BasedOnStyle: LLVM
# 访问说明符(public、private等)的偏移
AccessModifierOffset: -4
# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
AlignAfterOpenBracket: Align
# 连续赋值时,对齐所有等号
AlignConsecutiveAssignments: false
# 连续声明时,对齐所有声明的变量名
AlignConsecutiveDeclarations: false
# 右对齐逃脱换行(使用反斜杠换行)的反斜杠
AlignEscapedNewlines: Right
# 水平对齐二元和三元表达式的操作数
AlignOperands: true
# 对齐连续的尾随的注释
AlignTrailingComments: true
# 不允许函数声明的所有参数在放在下一行
AllowAllParametersOfDeclarationOnNextLine: false
# 不允许短的块放在同一行
AllowShortBlocksOnASingleLine: true
# 允许短的case标签放在同一行
AllowShortCaseLabelsOnASingleLine: true
# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All
AllowShortFunctionsOnASingleLine: None
# 允许短的if语句保持在同一行
AllowShortIfStatementsOnASingleLine: true
# 允许短的循环保持在同一行
AllowShortLoopsOnASingleLine: true
# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), 
# AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义)
AlwaysBreakAfterReturnType: None
# 总是在多行string字面量前换行
AlwaysBreakBeforeMultilineStrings: false
# 总是在template声明后换行
AlwaysBreakTemplateDeclarations: true
# false表示函数实参要么都在同一行,要么都各自一行
BinPackArguments: true
# false表示所有形参要么都在同一行,要么都各自一行
BinPackParameters: true
# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效
BraceWrapping:
  # class定义后面
  AfterClass: false
  # 控制语句后面
  AfterControlStatement: false
  # enum定义后面
  AfterEnum: false
  # 函数定义后面
  AfterFunction: false
  # 命名空间定义后面
  AfterNamespace: false
  # struct定义后面
  AfterStruct: false
  # union定义后面
  AfterUnion: false
  # extern之后
  AfterExternBlock: false
  # catch之前
  BeforeCatch: false
  # else之前
  BeforeElse: false
  # 缩进大括号
  IndentBraces: false
  # 分离空函数
  SplitEmptyFunction: false
  # 分离空语句
  SplitEmptyRecord: false
  # 分离空命名空间
  SplitEmptyNamespace: false
# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行)
BreakBeforeBinaryOperators: NonAssignment
# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), 
#   Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), 
#   Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom
#   注:这里认为语句块也属于函数
BreakBeforeBraces: Custom
# 在三元运算符前换行
BreakBeforeTernaryOperators: false
# 在构造函数的初始化列表的冒号后换行
BreakConstructorInitializers: AfterColon
#BreakInheritanceList: AfterColon
BreakStringLiterals: false
# 每行字符的限制,0表示没有限制
ColumnLimit: 0
CompactNamespaces: true
# 构造函数的初始化列表要么都在同一行,要么都各自一行
ConstructorInitializerAllOnOneLineOrOnePerLine: false
# 构造函数的初始化列表的缩进宽度
ConstructorInitializerIndentWidth: 4
# 延续的行的缩进宽度
ContinuationIndentWidth: 4
# 去除C++11的列表初始化的大括号{后和}前的空格
Cpp11BracedListStyle: true
# 继承最常用的指针和引用的对齐方式
DerivePointerAlignment: false
# 固定命名空间注释
FixNamespaceComments: true
# 缩进case标签
IndentCaseLabels: false
IndentPPDirectives: None
# 缩进宽度
IndentWidth: 4
# 函数返回类型换行时,缩进函数声明或函数定义的函数名
IndentWrappedFunctionNames: false
# 保留在块开始处的空行
KeepEmptyLinesAtTheStartOfBlocks: false
# 连续空行的最大数量
MaxEmptyLinesToKeep: 1
# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All
NamespaceIndentation: None
# 指针和引用的对齐: Left, Right, Middle
PointerAlignment: Right
# 允许重新排版注释
ReflowComments: true
# 允许排序#include
SortIncludes: false
# 允许排序 using 声明
SortUsingDeclarations: false
# 在C风格类型转换后添加空格
SpaceAfterCStyleCast: false
# 在Template 关键字后面添加空格
SpaceAfterTemplateKeyword: true
# 在赋值运算符之前添加空格
SpaceBeforeAssignmentOperators: true
# SpaceBeforeCpp11BracedList: true
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# 开圆括号之前添加一个空格: Never, ControlStatements, Always
SpaceBeforeParens: ControlStatements
# SpaceBeforeRangeBasedForLoopColon: true
# 在空的圆括号中添加空格
SpaceInEmptyParentheses: false
# 在尾随的评论前添加的空格数(只适用于//)
SpacesBeforeTrailingComments: 1
# 在尖括号的<后和>前添加空格
SpacesInAngles: false
# 在C风格类型转换的括号中添加空格
SpacesInCStyleCastParentheses: false
# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格
SpacesInContainerLiterals: true
# 在圆括号的(后和)前添加空格
SpacesInParentheses: false
# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响
SpacesInSquareBrackets: false
# 标准: Cpp03, Cpp11, Auto
Standard: Cpp11