配置VSCode的Clangd语言服务支持STM32开发

众所周知STM32开发一般使用Keil或者CubeIDE来管理工程和编译,但是这俩玩意的编辑器都不太现代化,用起来不太爽,所以也有很多人用VSCode来编写代码,只使用IDE来进行编译和调试(当然也有使用VSCode+全套开源工具链打包进行编写+编译+调试的,但是在win下实现起来尤为的不方便以前尝试过这里先按下不表)

然而vsc虽然很好用,但是他默认的C/C++插件功能就很难说是强大了,自动补全和语法检查经常傻傻的。一直也就这么凑合着用下来,今天一不小心给vsc的补全又玩炸了,调配置的时候突然想起这事,于是去搜了一下,说vsc其实是可以支持强大的clangd语言服务的…

谁想到这就是坠入大坑的开始…

懒得多介绍了,网上一堆,简单说clangd应该是通用的最强大的C/C++语言服务(有没有之一?)

性能和特性都比vsc默认的微软工具强很多

image-20250317232135358

安装clangd其实很简单,在拓展商店里直接装就行了,他还会提醒你本地没有语言服务,选择自动安装就可以给你配好了,没啥难度

然后按照网上的教程配置clangd的特性

image-20250317232844513

打开vsc的配置json

1
2
3
4
"C_Cpp.errorSquiggles": "disabled",
"C_Cpp.intelliSenseEngineFallback": "Disabled",
"C_Cpp.intelliSenseEngine": "disabled",
"C_Cpp.autocomplete": "disabled", // So you don't get autocomplete from both extensions.

这些代码用来禁用原来的拓展的语言服务,防止冲突。

image-20250317233034654

clangd路径已经被自动配置好了

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
"clangd.arguments": [
// 让 Clangd 生成更详细的日志
"--log=verbose",
// 输出的 JSON 文件更美观
"--pretty",
// 全局补全(输入时弹出的建议将会提供 CMakeLists.txt 里配置的所有文件中可能的符号,会自动补充头文件)
"--all-scopes-completion",
// 建议风格:打包(重载函数只会给出一个建议)
// 相反可以设置为detailed
"--completion-style=bundled",
// 跨文件重命名变量
"--cross-file-rename",
// 允许补充头文件
"--header-insertion=iwyu",
// 输入建议中,已包含头文件的项与还未包含头文件的项会以圆点加以区分
"--header-insertion-decorators",
// 在后台自动分析文件(基于 complie_commands,我们用CMake生成)
"--background-index",
// 启用 Clang-Tidy 以提供「静态检查」
"--clang-tidy",
// Clang-Tidy 静态检查的参数,指出按照哪些规则进行静态检查,详情见「与按照官方文档配置好的 VSCode 相比拥有的优势」
// 参数后部分的*表示通配符
// 在参数前加入-,如-modernize-use-trailing-return-type,将会禁用某一规则
"--clang-tidy-checks=cppcoreguidelines-*,performance-*,bugprone-*,portability-*,modernize-*,google-*",
// 默认格式化风格: 谷歌开源项目代码指南
// "--fallback-style=file",
// 同时开启的任务数量
"-j=2",
// pch优化的位置(memory 或 disk,选择memory会增加内存开销,但会提升性能) 推荐在板子上使用disk
"--pch-storage=memory",
// 启用这项时,补全函数时,将会给参数提供占位符,键入后按 Tab 可以切换到下一占位符,乃至函数末
// 我选择禁用
"--function-arg-placeholders=false",
// compelie_commands.json 文件的目录位置(相对于工作区,由于 CMake 生成的该文件默认在 build 文件夹中,故设置为 build)
"--compile-commands-dir=build"
]

加入这一坨clangd的特性配置

好了,搞定,看起来不难是吧…

但是你用这个配置打开一个工程目录…

image-20250317234441904

满眼一片红啊,啥都认不出来

原因也很简单,就是clangd没法正确检索工程的库文件。

vsc默认的C插件也有这个问题,所以一般会让你改成tag praser,然后就好了(

但是在clangd这里,坑就深了…

真正的折磨才刚刚开始

查阅资料发现,这玩意必须依赖一个叫做compile_commands.json的文件,里面记录了工程的目录结构,引用的库文件等,clangd依赖他来提供语言服务

这玩意咋生成呢?如果你的项目用的是cmake,那一切都很美好,

cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1

用这句就行了

然而很显然不管是keil还是cubeide用的都不是cmake(哭

keil是自己的编译器和管理方式,cubeide用的是make和makefile

那么这里有两个办法

如果你用的是keil

装一坨叫做arm keil studio pack的玩意

里面提供了一个插件可以直接导入keil的uvprojx文件,然后自动生成clangd所需的compile_commands.json文件

其实因为keil设计的这套方案本来就是配合的clangd语言服务嘛,自然给你都解决好了

image-20250317235020611

image-20250317235556732

看起来一切都很美好,没毛病,除了这坨插件有点臃肿之外

image-20250317235820190

但是如果你用的是CubeIDE…

首先,我们需要从makefile手动生成compile_commands.json

搜到有一个工具,叫做bear,可以通过make来生成compile_commands.json

image-20250318000509964

但是很遗憾,这玩意只支持linux版本(

本来打算放弃了,但是又发现这玩意有个windows的替代品(from clangd官网)

image-20250318000613523

那么我们安装这个玩意

image-20250318000630479

在makefile的路径下面试一试

python -m compiledb make all

很遗憾呢,Windows下面没有make…CubeIDE自己的make和gcc啥的是封在他的安装路径里面的,外面也调用不到

那么我们装一个make(此处过程省略,总之不管你用mingw还是Chocolatey还是啥…反正确保make命令是可用的就行了

然后再试一下…

image-20250318001737010

似乎成功了是吧,然后也生成了对应的compile_commands.json文件

image-20250318001758910

当然,我们可以把命令改成

python -m compiledb -n make all

不执行实际的make动作,只进行配置文件输出,防止影响工程实际代码(毕竟你的path里不一定有正确的gcc,鬼知道编译出什么玩意来)

然后把compile_commands.json这玩意放到工程的根目录下面,用vsc打开…

大功告成了…吗?

image-20250318002223851

事情往往没那么简单。。还是有报错。。

只能继续搜索,问google,问大d老师

看起来是因为cubeide的gcc使用了一个自定义的编译参数,clangd并不认识这玩意…

解决方法嘛

image-20250318002439292

手动修改compile_commands.json文件,把”-fcyclomatic-complexity”,都替换成空行

然后重新打开

image-20250318002716568

好吧…终于,你成功了=-=

但是 我不知道 这一切值得吗…

最终,我删掉了clangd,删掉了上面的那一大坨东西,重新把配置改回了C/C++插件…

可能唯一的意义就是,确实熟悉了一坨编译方法和Windows下配置环境的过程吧

谁知道呢

姑且放在这里吧,或者如果真的有人对这些闲的蛋疼的鼓捣有兴趣的话,可以来看看

以及,发现了一个项目可以自动把cubeide转成clangd的支持

https://github.com/alex-schulster/stm_lsp_nvim

很不错,满足了我的一切想象,但是…这玩意依然只支持linux(摔

image-20250318003024543