Knighthana
文章108
标签144
分类7

文章归档

clangd到底要咋配.md

clangd到底要咋配.md

clangd到底要咋配

clangd很好用,毋庸置疑;

但每当在一个新的环境上部署了clangd、或者在一个新的代码仓库中打开clangd,或者手里有几套交叉的编译环境的时候,

clangd对环境的纠结可以促使人快速从平静变成愤怒然后再变成平静;当看到clangd把一个C Header当做Objective C++来猜的时候,就应该知道,该请高人了;

以前提过clangd的配置文件,但是干活的时候还是经常“俺寻思这样能行”,现在的话,决定整理一套方案,来汇总这些零零散散的配置文件。

说的是哪个clangd

首先,虽然clangd只有一个,那就是What is clangd?,也就是作为LLVM项目一部分的Language Server(LSP Server)。

不过一般不直接用clangd,而是通过编辑器调用,最常用的编辑器是VSCode,我们一般通过插件功能调用clangd插件

文件?配置?顺序?

clangd的配置

优先级:从(最高1)到(最低4),越靠近启动指令,优先级越高

优先级 配置来源 存储位置 生效范围
1 命令行参数 编辑器配置(VSCode - clangd.arguments) 仅当前编辑器实例
2 项目配置文件 项目根目录的 .clangd 仅当前项目文件夹
3 用户全局配置 config.yaml (系统路径下) 当前用户的所有项目
4 默认行为 clangd 程序内建逻辑 全局

系统路径: - Linux类环境 ~/.config/clangd/config.yaml - Windows环境 %LocalAppData%\clangd\config.yaml (Roaming)

关键规则: - 覆盖关系:对于单一值的配置(如 CompilationDatabase),高优先级直接覆盖低优先级。 - 追加关系:对于列表值的配置(如 CompileFlags: AddQueryDriver),高优先级通常会追加在低优先级之后,clangd会尝试匹配列表里的每一项。

Compilation Database:

Compilation Database协议本质上是一个JSON格式的文件,惯例上命名为compile_commands.json,其顶层是一个“命令对象”的数组。每个对象代表一个源文件(即“翻译单元”)的编译配置。clangd正是通过解析这些信息来理解工程的。

所以整个协议都围绕着一个JSON文件,这是否也是一种单例模式

clangd遵循协议的标准方式,自动查找并解析compile_commands.json文件,从中提取编译所需的信息。它的核心逻辑如下: 1. 智能查找:clangd启动后,会寻找compile_commands.json文件,查找顺序通常是: - 通过--compile-commands-dir=<路径>命令指定的目录。 - 当前工作目录。 - 当前工作目录的父目录。 - 待分析的源文件所在目录及其父目录。 2. 精确匹配:找到文件后,clangd会解析其内容,并使用file字段作为索引,为当前打开的源文件匹配对应的“命令对象”。 3. 提取核心编译参数:clangd主要从匹配到的“命令对象”中提取argumentscommand字段里的信息。它利用这些信息来构建编译环境,从而理解代码,提供准确的代码补全、跳转和诊断等功能。

生成compile_commands.json的方法

这个文件可以自动生成,常见的方法有:

CMake:在运行CMake配置时,添加-DCMAKE_EXPORT_COMPILE_COMMANDS=ON选项即可。

Bear:一个通用的工具,通过拦截make或其他构建命令的编译器调用来生成数据库。

Clang 自身:编译时使用-MJ参数可以为每个源文件生成一个JSON片段,再将它们合并起来。

Bazel:需使用第三方工具,如hedronvision/bazel-compile-commands-extractor

一般来说,最常用的是CMake,而且这厮还带了一个效率贼高的Ninja-Build,所以就它了。

vscode的clangd插件的配置

VSCode的clangd插件是在启动进程时,通过命令行参数(CLI Arguments)将配置传递给clangd服务: - 过程:VSCode 启动时,会读取settings.json中的clangd.arguments数组。 - 执行:它在后台拉起clangd.exe(或Linux下的clangd)时,实际执行的命令类似: clangd --compile-commands-dir=build/msys2-to-win --query-driver=/usr/bin/gcc ... - 这种方式的本质:是实时注入,不改动磁盘上的任何配置文件。

所以该怎么排布这些文件

从开发者的角度看,工程是多变的,环境是迟钝的;

从工程的角度来看,对环境的需求是不变的;

文件 位置 远程/本地 作用
config.yaml %LocalAppData%~/.config 本地 设定基础的警告习惯、最常用的编译器
.clangd 项目根目录 远程 配置仅与项目密切相关且与本地无关的编译情景
settings.json 项目.vscode/ 本地 配置项目中与本地密切相关的场景
CMakePresets.json 项目根目录 远程 一般来说是配置场景
CMakeUserPresets.json 项目根目录 本地 inhertPreset之后,主要是本地的build环境
compile_commands.json 项目build* 本地 CMake生成的对clangd最好消化的配置文件

附录

clangd这个tag为什么全小写

查阅了clangd的网站,没有任何迹象表明创作者希望clangd首字母大写,尤其是:

clangd is based on the Clang C++ compiler, and is part of the LLVM project.

clangdClang同行出现时,前者不大写而后者大写;

根据“名从主人”原则,clangdc不应该大写。


Knighthana

2026/04/20