跳转至

VSCode for MacOS

Motivation

这是一个历史遗留问题。两年多前当我第一次接触到vscode时,就对如何配置c++文件夹很头疼。当时的解决办法是在网上找文档解析一顿乱抄,也不知道原因,反正大杂烩一通后就能运行了。

这样做的优点是能跑,很显然,缺点是能跑的补集 :)

这两年多了不少开发,对于 c++ / makefile / cmake 的使用有了更加广阔的了解和思考,这里正好借“刚回国没事干”的空窗期进行整理与复盘,应该很适合新手入门。

前言

这份文档适合:使用 Apple Silicon 芯片的MacOS机器,新手友好向

参考文档:

  1. yunfi's vscode config @XJTU
  2. xijie's Intel MacOS config @THU
  3. VSCode Docs

我会在每一个部分附上参考脚本,它们都是开箱即用的,你可以直接复制粘贴到你的项目中,项目构建结构:

alt text

Prerequisites

本文主要应用场景是 单文件cpp 的编译,并不一定适用于 CMake 等工具。

C++ for VSCode

VSCode对c++的配置是以文件夹(及其内部的文件系统)为覆盖单位,这点跟python不同。

python有全局,也有基于文件夹的虚拟环境(pyenv),也有池化的(conda)。

C++ for VSC 是基于文件夹的,可以给不同的项目文件夹建立不同的配置。

步骤:

  1. 使用 clang/lldb 编译和调试 (Part 1: Json is all you need)
  2. 使用 clangd 进行补全和检查 (Part 2: clangd for auto-complete and code-check)
  3. 安装并使用 C/C++ 插件 和 Code Runner 插件 (Part 3: Advanced)
    • 我们并不是用这两个提供编译等支持,而是需要它们的“一键跳转”等功能
    • 与编译无关,只是为了提升代码开发效率(尤其针对大项目)

项目构建规范:

Text Only
 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
❯ tree -L 2 -a
.
├── .DS_Store
├── .build
├── .clang-format
├── .venv
│   ├── bin
│   ├── include
│   ├── lib
│   ├── pyvenv.cfg
│   └── share
├── .vscode
│   ├── c_cpp_properties.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── compile_flags.txt
├── mathlib_dynamic
│   ├── lib
│   ├── main
│   ├── main.cpp
│   ├── mathlib.cpp
│   └── mathlib.h
└── mathlib_project
    ├── lib
    ├── main
    ├── main.cpp
    ├── mathlib.cpp
    └── mathlib.h

12 directories, 16 files

你可以自动忽略.venv / mathlib_dynamic / mathlib_project / .DS_Store 及其子文件系统

  1. 所有对c++的配置都在.vscode文件夹下
  2. compile_flags.txt是clang-format的配置文件,用于格式化代码
  3. .clang-format是clang-format的配置文件,用于格式化代码
  4. .build用于编译过程中生成的中间文件
Good Habit of using build/

把所有的可执行文件放到 ./build/ 文件夹下,这样可以避免污染项目根目录,也可以方便地清理编译产生的中间文件。

Json is all you need

Use clang/lldb to Compile and Debug

  1. 确保 clang++ 已经正确安装(通过 clang++ -v 可以验证)
    • 对于 macOS,运行 xcode-select --install 可以安装好本文用到的所有包
    • 对于 Linux,下载 llvm 包,大概率包含了本文用到的所有包
  2. vscode 已启用 CodeLLDB 插件(报错无法下载可以先按报错给的 url 用浏览器下载,然后手动安装)
  3. tasks.json,放入.vscode 文件夹中
  4. launch.json,放入.vscode 文件夹中
  5. 在文件夹里新建一个 .build 文件夹( macOS / Linux 必做)
  6. 按 F5 (FN + F5),就可以编译调试了
ICON不能用

这样的配置下,右上角不会有运行的那个小按钮。由于未知问题,这个又 C/C++ 插件提供的按钮不会同步 tasks.json 和 launch.json 中的配置,所以放弃使用了那个插件。

Whole View

在macOS上配置C++专有项目时,了解不同的JSON文件及其用途是非常重要的

我们会接触到以下四个json文件(自小向大看):

  1. tasks.json 定义如何构建项目 (自动化流水线执行) -> 自动化执行调试配置
  2. launch.json 配置调试设置操作 (调试器层面)
  3. c_cpp_properties.json 指定编译器和包含路径等信息(编译器层面)
  4. settings.json 调整VS Code编辑器的整体行为(编辑器层面)

tasks.json

用途:tasks.json用于定义构建任务。它存储了如何编译和构建C++项目的配置信息

主要参数:

  • version: JSON文件的版本
  • tasks: 一个任务数组,每个任务定义了构建过程的细节
  • label: 任务的名称
  • type: 任务类型(通常为shell或process)
  • command: 执行的命令(如编译器路径)
  • args: 传递给命令的参数(如源文件名和输出文件名)
  • problemMatcher: 用于解析编译器输出中的错误和警告的匹配器

参考脚本:

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
{
    "version": "2.0.0",
    "tasks": [
      {
        "type": "shell",
        "label": "C/C++: clang++ build active file",
        "command": "/usr/bin/clang++", // `which clang++` may help you find this path
        "args": [
          "--std=c++17",
          "-fcolor-diagnostics",
          "-fansi-escape-codes",
          "-g",
          "${file}",
          "-o",
          "${workspaceFolder}/.build/${fileBasenameNoExtension}"
          "-fstandalone-debug", // to enable viewing std::string etc. when using lldb on Windows or Linux 
        ],
        "options": {
          "cwd": "${fileDirname}"
        },
        "group": {
          "kind": "build",
          "isDefault": true
        },
        "detail": "Task generated by Debugger."
      }
    ]
  }
脚本解释 (懒得写了,扔给GPT解释了👀)

这个 JSON 配置是用于 Visual Studio Code (VSCode) 的任务配置文件,主要是定义了一个构建任务(使用 clang++ 编译 C++ 文件)。下面是对每个键值对的详细说明:

  1. version

    • 描述: 指定任务配置的版本
    • : "2.0.0" 表示使用的任务配置文件的版本
  2. tasks

    • 描述: 这是一个任务数组,定义了一个或多个任务。在本例中,只有一个任务对象
  3. type
    • 描述: 任务类型,这里指定为 shell,意味着任务将在 shell 中执行(如终端)
    • : "shell" 表示这个任务是一个 shell 类型的任务
  4. label
    • 描述: 任务的名称,用于标识任务,显示在 VSCode 的任务列表中
    • : "C/C++: clang++ build active file" 表示任务名称,用于标识这个任务的功能:用 clang++ 编译 C++ 文件
  5. command
    • 描述: 要执行的命令或程序。在本例中,使用的是 clang++ 来编译 C++ 文件
    • : "/usr/bin/clang++" 指定了 clang++ 编译器的路径。你可以使用 which clang++ 命令来查找它
  6. args
    • 描述: 一个数组,包含传递给命令的参数
      • --std=c++17: 指定 C++ 17 标准
      • -fcolor-diagnostics: 启用彩色输出错误和警告信息
      • -fansi-escape-codes: 启用 ANSI 转义码,用于显示颜色等格式化文本
      • -g: 启用调试信息生成
      • ${file}: 当前打开的文件路径,代表源代码文件
      • -o: 后面跟着输出文件路径
      • ${workspaceFolder}/.build/${fileBasenameNoExtension}: 指定输出文件的路径和名称,文件名去掉扩展名
      • -fstandalone-debug: 启用独立的调试支持,特别是对于 Windows 或 Linux 系统上的 lldb 调试器,允许查看 std::string 等类型
  7. options
    • 描述: 指定任务执行时的选项
      • cwd: 当前工作目录。"${fileDirname}" 表示源代码文件所在的目录
  8. group
    • 描述: 任务的分组信息,用于定义任务类型
      • kind: 任务的种类,这里是 build,表示这是一个构建任务
      • isDefault: 是否是默认任务。true 表示这是默认的构建任务
  9. detail
    • 描述: 任务的详细描述,通常用于提供任务的额外信息
    • : "Task generated by Debugger." 说明这是一个由调试器生成的构建任务

launch.json

用途:launch.json 用于配置调试设置。它定义了如何启动调试器以及调试时需要使用的程序

内容:

  • version: JSON文件的版本
  • configurations: 一个配置数组,每个配置定义了一个调试会话的细节
  • name: 配置名称
  • type: 调试器类型(例如,cppdbg)
  • request: 请求类型(通常为launch)
  • program: 要调试的可执行文件路径
  • args: 传递给程序的命令行参数
  • cwd: 当前工作目录
  • stopAtEntry: 是否在入口点停止
    • 程序在启动时是否在入口点(即 main 函数的开头)停止
    • stopAtEntry: true: 程序启动时会在 main 函数的第一行停止。这样可以让你在程序开始执行之前设置断点、检查状态,或执行其他调试操作
    • stopAtEntry: false: 程序启动时会直接运行,不会在 main 函数的入口点停下来
    • 如果没有显式指定 stopAtEntry,其默认值为 false

参考脚本:

JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "C/C++: clang++ build and debug active file customize",
      "type": "lldb",
      "request": "launch",
      "program": "${workspaceFolder}/.build/${fileBasenameNoExtension}",
      "args": [],
      "cwd": "${workspaceFolder}",
      "preLaunchTask": "C/C++: clang++ build active file"
    },
    {
      "name": "C/C++ Runner: Debug Session",
      "type": "lldb",
      "request": "launch",
      "args": [],
      "cwd": "/Users/huluobo/code_projects/vscode",
      "program": "/Users/huluobo/code_projects/vscode/build/Debug/outDebug"
    }
  ]
}
脚本解释 (懒得写了,扔给GPT解释了👀)

它定义了两种调试配置,分别是 clang++ 编译和调试的配置,以及一个示例的调试运行配置。每个配置是一个独立的对象,保存在 configurations 数组中:

1) 顶层属性

  • version: 版本号,指定了 launch.json 配置的版本。0.2.0 是较旧的版本,但仍然广泛使用
  • configurations: 这是一个数组,包含多个调试配置。每个调试配置是一个对象,可以定义调试会话的具体参数

2) 第一个配置对象 (Clang++ 编译和调试)

JSON
1
2
3
4
5
6
7
8
9
{
"name": "C/C++: clang++ build and debug active file customize",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/.build/${fileBasenameNoExtension}",
"args": [],
"cwd": "${workspaceFolder}",
"preLaunchTask": "C/C++: clang++ build active file"
}

这个配置是用来启动调试器并调试 C++ 程序的。各个属性的解释如下:

  • name: 配置的名称,显示在调试器的下拉框中,用于标识该调试配置
    • 例如:"C/C++: clang++ build and debug active file customize"
  • type: 指定调试类型。这里使用 lldb,表示使用 LLDB 调试器来进行调试(适用于 macOS 或 Linux 系统)
  • request: 调试请求类型。launch 表示启动程序并开始调试
  • program: 指定要调试的可执行程序路径
    • ${workspaceFolder} 是当前工作空间的根目录
    • ${fileBasenameNoExtension} 是当前打开文件的文件名(不包括扩展名)
    • 意味着编译后的程序将位于 .build 文件夹下,并使用当前文件的基本名称作为程序名称
  • args: 启动程序时传递给程序的命令行参数。在这个例子中为空数组,表示没有传递任何命令行参数
  • cwd: 设置程序运行时的当前工作目录。"${workspaceFolder}" 表示当前工作空间的根目录
  • preLaunchTask: 在启动调试之前运行的任务。这指定了一个构建任务,该任务会先编译源文件。在这里,它引用了之前定义的任务 C/C++: clang++ build active file,确保调试前先进行编译

3) 第二个配置对象 (调试会话示例)

JSON
1
2
3
4
5
6
7
8
{
"name": "C/C++ Runner: Debug Session",
"type": "lldb",
"request": "launch",
"args": [],
"cwd": "/Users/huluobo/code_projects/vscode",
"program": "/Users/huluobo/code_projects/vscode/build/Debug/outDebug"
}

这个配置定义了一个简单的调试会话,适用于在固定路径下运行并调试一个已编译的程序。

  • name: 调试会话的名称,显示在 VSCode 的调试配置下拉菜单中
    • 例如:"C/C++ Runner: Debug Session"
  • type: 使用 lldb 调试器
  • request: 调试请求类型,这里也是 launch,表示启动调试
  • args: 这个配置没有传递额外的命令行参数,因此是一个空数组
  • cwd: 指定程序的工作目录。在这个例子中是 /Users/huluobo/code_projects/vscode,即程序运行时的目录
  • program: 指定要调试的可执行文件路径。在这里它指向 /Users/huluobo/code_projects/vscode/build/Debug/outDebug,即要调试的已编译的程序

总结

这段 launch.json 配置文件包含了两种调试配置:

  1. 一个自定义的配置,先通过任务构建文件,再调试当前活跃文件
  2. 一个固定路径的调试配置,调试指定路径下的已编译程序

它们都使用 LLDB 调试器,并且可以在 VSCode 中选择并启动调试。

c_cpp_properties.json

用途:用于配置C/C++扩展的设置,包括编译器路径、包含路径和语言标准等

内容:

  • configurations: 一个配置数组,每个配置用于指定不同平台或项目设置
  • name: 配置名称(如平台名称)
  • includePath: 包含路径数组,指定编译时需要查找头文件的位置
  • defines: 定义宏的数组
  • compilerPath: 编译器路径
  • cppStandard: C++标准版本(如C++17)

参考脚本:

JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "configurations": [
    {
      "name": "macos-clang-arm64",
      "includePath": [
        "${workspaceFolder}/**"
      ],
      "compilerPath": "/usr/bin/clang",
      "cStandard": "${default}",
      "cppStandard": "${default}",
      "intelliSenseMode": "macos-clang-arm64",
      "compilerArgs": [
        ""
      ]
    }
  ],
  "version": 4
}

settings.json

用途:它并不是专门给C++项目用的,其本身是全局配置使用的。但它存储VS Code用户或工作区级别的设置,其中包含对于C++的配置,that's why we mention it here.

内容:可以包括各种设置,例如编辑器行为、主题、扩展配置等

参考脚本:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
{
  "files.associations": {
    "iostream": "cpp",
    "cstring": "cpp",
    "algorithm": "cpp",
    "queue": "cpp",
    "iomanip": "cpp",
    "__config": "cpp"
  },
  "C_Cpp_Runner.cCompilerPath": "clang",
  "C_Cpp_Runner.cppCompilerPath": "clang++",
  "C_Cpp_Runner.debuggerPath": "lldb",
  "C_Cpp_Runner.cStandard": "",
  "C_Cpp_Runner.cppStandard": "",
  "C_Cpp_Runner.msvcBatchPath": "",
  "C_Cpp_Runner.useMsvc": false,
  "C_Cpp_Runner.warnings": [
    "-Wall",
    "-Wextra",
    "-Wpedantic",
    "-Wshadow",
    "-Wformat=2",
    "-Wcast-align",
    "-Wconversion",
    "-Wsign-conversion",
    "-Wnull-dereference"
  ],
  "C_Cpp_Runner.msvcWarnings": [
    "/W4",
    "/permissive-",
    "/w14242",
    "/w14287",
    "/w14296",
    "/w14311",
    "/w14826",
    "/w44062",
    "/w44242",
    "/w14905",
    "/w14906",
    "/w14263",
    "/w44265",
    "/w14928"
  ],
  "C_Cpp_Runner.enableWarnings": true,
  "C_Cpp_Runner.warningsAsError": false,
  "C_Cpp_Runner.compilerArgs": [],
  "C_Cpp_Runner.linkerArgs": [],
  "C_Cpp_Runner.includePaths": [],
  "C_Cpp_Runner.includeSearch": [
    "*",
    "**/*"
  ],
  "C_Cpp_Runner.excludeSearch": [
    "**/build",
    "**/build/**",
    "**/.*",
    "**/.*/**",
    "**/.vscode",
    "**/.vscode/**"
  ],
  "C_Cpp_Runner.useAddressSanitizer": false,
  "C_Cpp_Runner.useUndefinedSanitizer": false,
  "C_Cpp_Runner.useLeakSanitizer": false,
  "C_Cpp_Runner.showCompilationTime": false,
  "C_Cpp_Runner.useLinkTimeOptimization": false,
  "C_Cpp_Runner.msvcSecureNoWarnings": false
}

clangd for auto-complete and code-check

  1. 确保已安装 clangd(应该和 clang++ 在一个包里的,通过 clangd --version 检查)
  2. 安装插件 clangd
  3. 在工作区根目录下新建一个 compile_flags.txt,这是用来为 clangd 指定参数的,比如使用的标准或是标准库路径之类。内容就是编译选项,一行一个。这里只写了一个标准作为例子
    Text Only
    1
    --std=c++17
    

Advanced