# 代码自动提示：clangd 与 VS Code 入门

> 用最小 VS Code 配置连接 clangd 与真实编译数据库，排查找不到头文件、宏不一致和跳转失败。

作者：[汤国放](https://tonwork.fun/#person)
发布日期：2024-07-06
更新日期：2026-10-08
原文：https://tonwork.fun/blog/%E4%BB%A3%E7%A0%81%E8%87%AA%E5%8A%A8%E6%8F%90%E7%A4%BA-clangd-vscode%E5%85%A5%E9%97%A8/

---

clangd 是基于 Clang 的 C/C++ 语言服务器，负责补全、跳转、诊断和重构；它不会替代 GCC 或 Clang 的工程构建。想让编辑器理解代码，先给它真实编译参数，再调补全选项，这是我更推荐的顺序。[clangd 官方入门](https://clangd.llvm.org/installation.html)

## 先准备可用的编译数据库

安装 clangd 和 VS Code 的 `llvm-vs-code-extensions.vscode-clangd` 扩展，确认终端能找到程序：

```sh
clangd --version
```

不要照抄旧教程中的 `clangd-12` 路径，填本机实际安装位置。CMake 工程可在配置时启用 `CMAKE_EXPORT_COMPILE_COMMANDS`；Bazel 工程可使用 Hedron extractor，但 WORKSPACE/Bzlmod 接入应以该仓库当前说明及项目版本为准。[CMake 生成方式](https://tonwork.fun/blog/compile_commands-json-%E7%AE%80%E6%98%93%E7%A7%91%E6%99%AE%E4%B8%8E%E7%BC%96%E8%AF%91%E9%80%89%E9%A1%B9%E8%A7%A3%E9%87%8A/)、[Hedron 上游说明](https://github.com/hedronvision/bazel-compile-commands-extractor)

## VS Code 保留一份最小配置

在工程 `.vscode/settings.json` 中配置：

```json
{
  "clangd.path": "clangd",
  "clangd.arguments": ["--background-index", "--clang-tidy"],
  "C_Cpp.intelliSenseEngine": "disabled"
}
```

最后一项只在同时安装 Microsoft C/C++ 扩展时需要，用来避免两个语言服务重复提供诊断；它不禁用调试器。复杂参数先不加，旧版本命令行选项可能已经变化，先通过 `clangd --help` 核对。[VS Code 扩展官方说明](https://clangd.llvm.org/installation.html#visual-studio-code)

clangd 会搜索源码所在目录及父目录的数据库，常规 `build/` 目录也会被考虑。如果数据库在其他目录，可以在工程根目录放 `.clangd`：

```yaml
CompileFlags:
  CompilationDatabase: build
```

该相对路径相对于这份 `.clangd` 文件的位置解析。使用远程开发时，clangd、数据库和工具链路径都要在远端成立。[clangd 配置文档](https://clangd.llvm.org/config#compilationdatabase)

## 用一次命令把问题缩小

```sh
clangd --check=src/main.cpp --compile-commands-dir=build --log=verbose
```

我会按日志里的实际命令排查，而不是反复重启编辑器：

| 现象 | 优先检查 |
| --- | --- |
| 日志是 `Generic fallback command` | 数据库目录、当前源码的记录以及 `file` 路径 |
| 只有项目头文件找不到 | `-I` 目录是否存在，生成头文件是否已构建，数据库是否来自另一台机器 |
| `iostream` 等系统头文件找不到 | 编译器绝对路径、目标平台、SDK/sysroot，clangd 使用的工具链是否一致 |
| `#ifdef` 分支与构建不一致 | 当前记录的 `-D` / `-U` 和所选构建配置 |
| 头文件跳转结果异常 | 查看它借用了哪个源文件的命令，再确认包含关系和配置 |

如果自定义 GCC 交叉工具链能编译，而 clangd 仍找不到系统头，可以给 `clangd.arguments` 加上针对实际可信编译器的 `--query-driver=/opt/toolchain/bin/aarch64-linux-gnu-g++`。它允许 clangd 执行数据库中的匹配编译器，以查询系统头路径；这个参数不会替你安装工具链，也不是随便填一个路径就能修好。[系统头文件与 query-driver](https://clangd.llvm.org/guides/system-headers#query-driver)

本次用 macOS 自带 clangd 检查了带 `-DAPP_DEBUG=1` 的最小数据库，实际日志选中了 CDB 并报告 0 errors。这验证了数据库到解析器这条链路，VS Code UI 和大型 Bazel 工程仍需按自己的环境核对。

想先了解每个参数代表什么，回到 [compile_commands.json 科普](https://tonwork.fun/blog/compile_commands-json-%E7%AE%80%E6%98%93%E7%A7%91%E6%99%AE%E4%B8%8E%E7%BC%96%E8%AF%91%E9%80%89%E9%A1%B9%E8%A7%A3%E9%87%8A/)；想找一个可以直接编译的练习，试试 [weak_ptr 生命周期示例](https://tonwork.fun/blog/c-%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88-weak_ptr-%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%97/)。这些文章也收在 [C++ 与工具链导读](https://tonwork.fun/topics/cpp-toolchain/)。
