让 Clangd 支持 GCC 的 C++23 Std Module

本文主要记录在 Arch Linux 上使用 GCC 15.2.1 编译器编译包含 import std; 的 C++23 标准模块(std module)代码时,如何让 Clangd 正常工作——即 import std; 不再被标记为红色波浪线提示“Module 'std' not found”,并且能够正常提供其中符号的悬停(Hover)提示。

使用的工具版本如下:

 - GCC: 15.2.1
 - Clangd: 22.0.0git def8ecbda9f146d5ba5bbc8c92f7d5ccd242ad2b
 - VS Code: 1.106.1
 - VS Code 中的 Clangd 插件: 0.2.0
 - Bear: 3.1.6

如你所见,Clangd 官方目前最新的稳定版本是 21.1.6,但本次实验需自行从 Git 仓库编译开发中的 22.0.0 版本。实测表明,21.x 版本容易出现部分源代码文件中的符号无法正常解析的问题。

VS Code 的 C++ 插件使用的是 Clangd(LLVM)。Microsoft 官方的 C/C++ 插件表现如何,可自行尝试。

首先,我们创建一个最小可行项目。运行以下命令:

cp /usr/include/c++/15.2.1/bits/std.cc .
cp /usr/include/c++/15.2.1/bits/std.compat.cc .

将系统中 GCC 提供的两个用于 C++23 标准模块的关键文件复制到当前目录。

接着新建一个 main.cpp 文件,内容如下:

import std;
import std.compat;

int main()
{
    std::cout << "Hello C++23 Std Module in GCC!\n";
}

并编写对应的 Makefile:

CXX := /usr/bin/g++
CXXFLAGS := -std=c++26 -fmodules

STDCC := std.cc
STDCOMPATCC := std.compat.cc

main: gcm.cache/std.gcm gcm.cache/std.compat.gcm main.cpp
    $(CXX) $(CXXFLAGS)    -o main           main.cpp

gcm.cache/std.gcm: $(STDCC)
    $(CXX) $(CXXFLAGS) -c -o std.o          $(STDCC)

gcm.cache/std.compat.gcm: $(STDCOMPATCC)
    $(CXX) $(CXXFLAGS) -c -o std.compat.o   $(STDCOMPATCC)

.PHONY: clean

clean:
    rm -rf .cache gcm.cache main *.o compile_commands.json

下一步,使用 Bear 生成 compile_commands.json,同时尝试编译,运行:

bear -- make

这会在当前目录下生成 compile_commands.json 文件,该文件将被 Clangd 识别并使用。同时会编译源文件。正常情况下应无报错,当前目录下会生成 std.ostd.compat.omaingcm.cache/ 目录。Make 实际执行了以下命令:

/usr/bin/g++ -std=c++26 -fmodules -c -o std.o          std.cc
/usr/bin/g++ -std=c++26 -fmodules -c -o std.compat.o   std.compat.cc
/usr/bin/g++ -std=c++26 -fmodules    -o main           main.cpp

接着,新建 .clangd 配置文件,内容如下:

If:
    PathMatch: [.*\.h, .*\.cpp]
CompileFlags:
    Add: [-std=c++26, -fmodules, -Xclang, -fbuiltin-headers-in-system-modules]
    Compiler: g++

在 VS Code 中按 Ctrl+, 打开设置,搜索 “clangd”,找到 “Clangd: Arguments” 选项,添加以下两条参数:

--enable-config
--experimental-modules-support

如果你确实自行编译了 Clangd 22.0.0,可能还需要修改 “Clangd: Path” 设置,将其指向你编译出的 Clangd 可执行文件路径。

此时,用 VS Code 打开 main.cpp,应该会看到 import std; 下的红色波浪线已经消失,将光标悬停在 cout 上时,也能正常显示悬停提示框。

以下是一些可能出现的常见问题:

  1. 请确保 compile_commands.json 中包含正确的内容,而不是只有 []。这可以通过执行 make clean; make 来解决。
  2. 请确保确实将系统目录中的 std.ccstd.compat.cc 这两个文件复制到了当前目录中,而不是在 Makefile 中直接引用系统路径下的文件,否则可能导致 Clangd 解析失败。
  3. 请确保 Clangd 能读取到的 .clangd 配置文件中,CompileFlags 已正确添加了 -fmodules-Xclang-fbuiltin-headers-in-system-modules 这几个选项,特别是最后一个。否则可能在 Clangd 日志中看到与 inttypes.h 相关的报错。
  4. 请确保在 VS Code 的 Clangd 插件设置中已添加 --experimental-modules-support 参数,否则 Clangd 可能在多次重启失败后自动停止运行。

希望这篇文章对你有所帮助!如果你仍有疑问,欢迎通过电子邮件等方式与我分享你的实验经历。