快捷搜索:  汽车  科技

cls在c语言中使用方法(使用Clangd提升C代码编写体验)

cls在c语言中使用方法(使用Clangd提升C代码编写体验)除了报错、跳转、代码补全这些大家都有的功能外,clangd还提供一些非常好用的特色功能。clangd是llvm项目推出的C 语言服务器,通过LSP(Language Server Protocal)协议向编辑器如vscode/vim/emacs提供语法补全、错误检测、跳转、格式化等等功能。C 的LSP曾经是cquery ccls clangd三足鼎立。但是clangd支持clang-tidy实时检查的功能是另外两者不具备的,而且cquery和ccls都是单个开发者主导的项目,clangd背后则是有llvm的背书。目前来看,“姓赵”的clangd在这场c lsp赛跑中已经有了不小的领先优势。C 的通用性使它不可避免地成为了一门复杂的语言,尤其是在“现代”C 诞生之后,C 标准委员会源源不断地向C 加入新特性。不可否认,自由度和多面性正是C 的魅力所在,但是它们也大大地增

作者:jinshang,腾讯WXG后台开发工程师

| 导语 工欲善其事,必先利其器。LLVM项目推出的clangd拥有稳定的体验、完善的功能和活跃的社区,它作为一个稳定高效的C 代码插件可以成倍地提升我们的代码编写体验,是每个C 程序员提升代码效率的不二之选。

简介

C 是一门通用的语言,你可以用C 写各式各样的程序,就像C 维基百科第一段话所说

C 是一种被广泛使用的计算机程序设计语言。它是一种通用程序设计语言,支持多重编程范式,例如过程化程序设计、数据抽象)、面向对象程序设计、泛型程序设计和设计模式)等。

C 的通用性使它不可避免地成为了一门复杂的语言,尤其是在“现代”C 诞生之后,C 标准委员会源源不断地向C 加入新特性。不可否认,自由度和多面性正是C 的魅力所在,但是它们也大大地增加了C 程序员们的心智负担,在C 11之前,也许《21天精通C 》还存在些许的可能性(这本书并不存在,我瞎编的),但是等再过几年C 20成为主流后,《21年精通现代C 》也许会成为下一本畅销书。(关于现代C 好用的特性,可以阅读我的这篇文章:C 17在业务代码中最好用的十个特性。

C 变得越来越难写,但编译器们却不会阻止我们写出五花八门的代码,gcc、Clang也不会像rustc一样对你的代码指指点点,只会任由你的程序放飞自我。对于Jeff Dean这样的大神来说这是自然而然的,毕竟从来都是他警告编译器(这是Jeff Dean的众多恶搞梗之一,参考:https://www.zhihu.com/question/22081653/answer/20593104)。而对于我们这些还没有“精通”C 的程序员来说,如果有一个实时的C 代码检查工具在我们写代码的同时在旁边指指点点,教我们写代码,它无疑可以大大提升我们的编程效率和体验。

在业界,C 常用的代码检查工具有cpplint,coverity,clang-tidy(clangd背后也是通过clang-tidy检查,这里是指clang-tidy二进制本身独立使用)等,它们往往无法兼顾代码检查的完整性和实时性。如果要做到完整检查,就需要编译代码,通过代码的IR表示去分析逻辑流,比如coverity,这种检查往往是CI/CD流水线的一部分,不能实时检查。而cpplint则是不编译代码,这是通过词法分析,检查代码格式不符合标准的地方或者局部的问题,没有办法检测代码的逻辑错误。如果要兼顾完整性和实时性,就需要一个编译器在后台实时地编译我们的代码,而clangd恰好就提供这种功能。

什么是clangd

clangd是llvm项目推出的C 语言服务器,通过LSP(Language Server Protocal)协议向编辑器如vscode/vim/emacs提供语法补全、错误检测、跳转、格式化等等功能。C 的LSP曾经是cquery ccls clangd三足鼎立。但是clangd支持clang-tidy实时检查的功能是另外两者不具备的,而且cquery和ccls都是单个开发者主导的项目,clangd背后则是有llvm的背书。目前来看,“姓赵”的clangd在这场c lsp赛跑中已经有了不小的领先优势。

clangd提供的特色功能

除了报错、跳转、代码补全这些大家都有的功能外,clangd还提供一些非常好用的特色功能。

自动插入头文件

clangd的代码补全可以搜索你的整个代码库,即使是没有被include进来的变量也会覆盖到。而且在补全时,它会自动帮你填上合适的namespace和头文件:

cls在c语言中使用方法(使用Clangd提升C代码编写体验)(1)

clang-format

业界大型的C 代码项目一般都会自带clang-format配置,作为clang家族的一员,clangd可以提供自动的clang-format格式化:

cls在c语言中使用方法(使用Clangd提升C代码编写体验)(2)

类型提示

从clangd-14开始,clangd提供变量自动的类型提示,从此可以大胆地使用auto了:

cls在c语言中使用方法(使用Clangd提升C代码编写体验)(3)

Clang-tidy代码检查

先上一组效果图,看看clangd都能实时检测出哪些问题,错误最后标注了(fix available)的都是clangd可以自动修复的问题:

1.性能问题,如多余的拷贝,无效的move,低效的算法等:

cls在c语言中使用方法(使用Clangd提升C代码编写体验)(4)

2.潜在的错误,如use-after-move,无限循环,错误算法等:

cls在c语言中使用方法(使用Clangd提升C代码编写体验)(5)

3.可读性问题,如隐式bool转换,函数参数不统一,变量命名规则等:

cls在c语言中使用方法(使用Clangd提升C代码编写体验)(6)

4.现代化C ,如使用auto,using,override等现代C 特性:

cls在c语言中使用方法(使用Clangd提升C代码编写体验)(7)

(vscode Community Material配色 Error Lens插件,Error Lens插件用于将错误提示直接展示在代码后)

如何使用安装

clangd有三种安装方式:

系统包管理:如mac系统可使用brew install llvm,debian/ubuntu可使用sudo apt-get install clangd-14 等等

手动下载二进制:可以在https://github.com/clangd/clangd/releases/tag/15.0.0手动下载最新版本的二进制

手动编译:可以参考https://github.com/llvm/llvm-project/tree/main/clang-tools-extra/clangd#building-and-testing-clangd从源码编译

个人更推荐后两种方式,因为最新的功能比如类型提示要在新版本的clangd才有

配置编辑器

以vscode为例,首先在插件市场安装clangd插件,接下来在vscode配置中添加如下几行

"clangd.arguments": [ "--clang-tidy" // 开启clang-tidy "--all-scopes-completion" // 全代码库补全 "--completion-style=detailed" // 详细补全 "--header-insertion=iwyu" "--pch-storage=disk" // 如果内存够大可以关闭这个选项 "--log=error" "--j=5" // 后台线程数,可根据机器配置自行调整 "--background-index" ] "clangd.path": "<安装的clangd地址>" "[cpp]": { "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" } 项目配置

clangd需要知道如何编译你的项目,因此需要一个“编译数据库”,通常情况下我们需要向clangd提供一个compile_commands.json文件,这个文件的生成需要依赖你的编译系统:

CMAKE:cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 添加这个参数即可

BAZEL:https://github.com/hedronvision/bazel-compile-commands-extractor可以使用这个插件

其他:大多数编译系统都会提供自己的compile commands生成方式,如果没有,或者是很老的项目,则可以通过https://github.com/rizsotto/Bear插件获取

WXG Patchbuild:微信的patchbuild自带支持compile_commands.json生成,在正常的编译命令后加上--download-genfiles --compile-command-query=--merge后运行,patchbuild会把当前目标的compile_commands.json生成,并与本地的~/QQMail/compile_commands.json合并,供clangd使用:

patchbuild build --download-genfiles --compile-command-query=--merge :<目标>

对于每一个源文件,clangd会自动向上层,以及每层的build文件夹寻找compile_commands.json,如果你生成的文件在其他地址,可以通过ln -s ~/myproject-build/compile_commands.json ~/myproject/ 创建软连接解决。

clang-tidy配置

clang-tidy的各项检查可以通过一个配置文件配置,在项目的根目录下添加一个.clang-tidy(这就是文件名,".clang-tidy"),可以参考我的,然后根据需求自己搭配:

--- Checks: > -* bugprone-* google-* misc-* modernize-* performance-* portability-* readability-* -modernize-use-trailing-return-type -bugprone-lambda-Function-name -google-runtime-references -readability-magic-numbers -bugprone-easily-swappable-parameters -readability-identifier-length -bugprone-narrowing-conversions # Turn all the warnings from the checks above into errors. WarningsAsErrors: "performance-* bugprone-*" CheckOptions: - { key: readability-identifier-naming.NamespaceCase value: lower_case } - { key: readability-identifier-naming.ClassCase value: CamelCase } - { key: readability-identifier-naming.StructCase value: CamelCase } - { key: readability-identifier-naming.TemplateParameterCase value: aNy_CasE } - { key: readability-identifier-naming.FunctionCase value: aNy_CasE } - { key: readability-identifier-naming.VariableCase value: lower_case } - { key: readability-identifier-naming.ClassMemberCase value: lower_case } - { key: readability-identifier-naming.ClassMemberSuffix value: _ } - { key: readability-identifier-naming.PrivateMemberSuffix value: _ } - { key: readability-identifier-naming.ProtectedMemberSuffix value: _ } - { key: readability-identifier-naming.EnumConstantCase value: CamelCase } - { key: readability-identifier-naming.EnumConstantPrefix value: k } - { key: readability-identifier-naming.ConstexprVariableCase value: CamelCase } - { key: readability-identifier-naming.ConstexprVariablePrefix value: k } - { key: readability-identifier-naming.GlobalConstantCase value: CamelCase } - { key: readability-identifier-naming.GlobalConstantPrefix value: k } - { key: readability-identifier-naming.MemberConstantCase value: CamelCase } - { key: readability-identifier-naming.MemberConstantPrefix value: k } - { key: readability-identifier-naming.StaticConstantCase value: CamelCase } - { key: readability-identifier-naming.StaticConstantPrefix value: k } - { key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic value: 1 } - { key: readability-function-cognitive-complexity.Threshold value: 100 }

对于每一项配置的含义,可以参考:https://clang.llvm.org/extra/clang-tidy/checks/list.html

同时也可以参考开源项目的配置,如google cloud的:https://github.com/googleapis/google-cloud-cpp/blob/main/.clang-tidy 或者apache arrow的:https://github.com/apache/arrow/blob/master/.clang-tidy

clang-format配置

同理,在项目根目录下添加.clang-format文件,用与clangd自动格式化,可以参考开源项目的修改,比如:https://github.com/googleapis/google-cloud-cpp/blob/main/.clang-format和https://github.com/apache/arrow/blob/master/.clang-format

总结

工欲善其事,必先利其器。LLVM项目推出的Clangd拥有稳定的体验、完善的功能和活跃的社区,它作为一个稳定高效的C 代码插件可以成倍地提升我们的代码编写体验,是每个C 程序员提升代码效率的不二之选。

猜您喜欢: