# VSCode 使用 Clangd 插件 Clangd 是一个基于 Clang 的语言服务器,它提供了代码智能感知和导航功能。通过与 VSCode 集成,可以实现以下功能: - 代码补全和自动提示:Clangd 可以根据代码上下文提供准确的补全建议和自动提示,帮助开发者快速编写代码。 - 代码跳转和导航:Clangd 可以识别代码中的符号引用、函数调用等,并支持跳转到定义、查看声明等操作,便于阅读和理解复杂的内核源代码。 - 实时错误和警告检查:Clangd 可以实时检查代码中的语法错误、潜在问题和警告信息,帮助开发者及早发现和修复问题。 - 重构支持:Clangd 提供了一些重构功能,如重命名变量、提取函数等,可以简化代码重构的过程。 需要代码分析和跳转的话要安装 clangd,需要代码格式化则需要安装 clang-format,并能够在系统 PATH 种找到它们。 在 VSCode 中使用 Clangd 需要先安装 clangd (LLVM) 插件,然后使用源码目录下的 .clang-format,.clangd 或 .vscode/settings.json 进行项目配置。 ## 1. 基本使用配置 ### 1.1. 使用 .clangd 文件方式 clangd 的配置文件为源码路径下的 .clangd 文件。 可通过: ```bash Ctrl+Shift+P -> clangd: open project configuration file ``` 打开项目 .clangd 文件, 参考格式如下: ```clangd # 提示嵌入,不使用函数参数嵌入提示 #InlayHints: # Designators: Yes # Enabled: Yes # ParameterNames: No # DeducedTypes: Yes CompileFlags: Add: - -xc - -ID:/Path/to/project/source/User Remove: - -forward-unknown-to-host-compiler - --generate-code* - -rdc=* - -Xcompiler* ``` 其中 -x 为 gcc 参数,用于忽略源代码文件扩展名,并使用 -x 参数指定的语言类型。如果源码文件不是标准后缀名称(.c,.cpp )或语法与扩展名不符,则 gcc 编译器便不能通过后缀名判断语言类型,此时可以通过该参数指定语言类型。取值可以为: - -xc - -xc++ - -xobjective-c - -xc-header - -xcpp-output - -assembler - -assembler-with-cpp -I 为 gcc 指定库头文件路径的参数。 #### 1.1.1 Qt 的 .clangd 配置参考 ```clangd CompileFlags: Add: - -xc++ - -I/usr/include/aarch64-linux-gnu/qt5 - -I/usr/include/aarch64-linux-gnu/qt5/QtCore - -I/usr/include/aarch64-linux-gnu/qt5/QtWidgets ``` ### 1.2. 使用 .vscode/settings.json 方式 创建:.vscode/settings.json 文件,参考配置格式如下: ```json { "clangd.fallbackFlags": [ "-xc", "-I${workspaceFolder}/User", ], } ``` ### 1.3. clang-format 使用代码格式化功能需要在 VSCode User Setting 中使能 Text Editor->Formatting->Formate On Type。 clang-format 的配置文件为源码路径下的 .clang-format 文件,几个配置参考如下: ```clang-format BasedOnStyle: LLVM UseTab: Never IndentWidth: 4 TabWidth: 4 # 最外层大括号换行 # BreakBeforeBraces: Linux BreakBeforeBraces: Allman AllowShortIfStatementsOnASingleLine: true IndentCaseLabels: false ColumnLimit: 120 ``` ```clang-format --- Language: Cpp #圆括号之后,多行内容,进行对齐 AlignAfterOpenBracket: Align #连续赋值时,对齐所有等号 AlignConsecutiveAssignments: true #连续声明时,对齐所有声明的变量名 AlignConsecutiveDeclarations: true #连续宏定义时,对齐所有定义值 AlignConsecutiveMacros: AcrossEmptyLinesAndComments #AlignOperands Align将对齐分割到多行上的单个表达式的操作数 AlignOperands: Align #对齐连续的尾随的注释 AlignTrailingComments: true #允许将一个函数声明的所有参数移到下一行. AllowAllParametersOfDeclarationOnNextLine: false #将简单的语句块放到一个单行 AllowShortBlocksOnASingleLine: false #if (a) return;放单行 属性:Never、WithoutElse没有else的可以放单行、OnlyFirstIf只有第一个if放单行、AllIfsAndElse总是把简短的if, else if和else语句放在同一行。 AllowShortIfStatementsOnASingleLine: Never #BinPackArguments:如果为false,函数调用的参数要么全部在同一行,要么各有一行。 BinPackArguments: false #BinPackParameters:如果为false,函数声明或函数定义的参数将全部在同一行或各有一行。 BinPackParameters: false BreakBeforeBraces: Custom # 控制单独的大括号换行事件,只有当BreakBeforeBraces设置为Custom时才有效 BraceWrapping: #使控制语句(if/for/while/switch/..)换行。 AfterControlStatement: true #使枚举定义换行。 AfterEnum: true #使函数定义换行。 AfterFunction: true #使结构定义换行。 AfterStruct: true #使共同体定义换行。 AfterUnion: true #在else之前换行。 BeforeElse: true #换行大括号缩进。 IndentBraces: false #空函数是否可以放在单行:flase允许 true不允许 SplitEmptyFunction: true #空类,结构或联合主体是否可以放在单行:flase允许 true不允许 SplitEmptyRecord: true #空namespace是否可以放在单行:flase允许 true不允许 SplitEmptyNamespace: true SpaceBeforeParens: Custom #控制圆括号前的单独空格,只有当SpaceBeforeParens设置为Custom时才有效 SpaceBeforeParensOptions: #在控制语句关键字(for/if/while…)和开括号之间放置空格 AfterControlStatements: true #在函数声明名称和开括号之间不允许使用空格 AfterFunctionDeclarationName: false #指针对齐:右 PointerAlignment: Right # 三元运算符将被放置在换行后 BreakBeforeTernaryOperators: true #每行字符的限制,0表示没有限制 ColumnLimit: 0 #缩进空格宽度:4 IndentWidth: 4 #保留在赋值操作符之前的空格 SpaceBeforeAssignmentOperators: true #不要排序include的头文件 SortIncludes: Never #允许重新排版注释 ReflowComments: true #尾行注释前的空格数 SpacesBeforeTrailingComments: 2 #连续空行的最大数量 MaxEmptyLinesToKeep: 1 #使用tab字符: Never从不使用, ForIndentation仅在缩进时使用制表符, ForContinuationAndIndentation, Always UseTab: Never #SpacesInParentheses如果为真(true), 将会在“(”之后和“)”之前插入空格。 SpacesInParentheses: false #SpacesInSquareBrackets如果为真(true),将会在“[”之后和“]”之前插入空格。 SpacesInSquareBrackets: false ``` 手动格式化当前文件:右击当前打开的文档,选择“格式化文档”。 如果想格式化一整个文件夹,可以安装 VSCode 的 format files(by:jbockle)插件,然后在文件窗口种右击要格式化的文件夹,选择“Start Formate Files: This Folder”。 ### 1.4. 其他配置 #### 1.4.1 打开或关闭函数参数提示 (inlay hints) 编码阶段嵌入的函数参数 hints 比较干扰实现,可以通过 Ctrl+Shift+P 呼出 VSCode 命令,点击“clangd: Toggle inlay hints”进行切换即可。 ## 2. 使用 VSCode+Clangd 开发 Linux 内核 如果直接使用 VSCode+Clangd 阅读内核代码的话,会存在一个问题:很难确定哪些 Linux 内核源码源码文件被编译使用了,哪些没有。此时使用 Bear 工具配合使用就可以很好的解决这个问题。Bear 是 Build EAR 的缩写,[官方](https://github.com/rizsotto/Bear)介绍如下: ```md Bear is a tool that generates a compilation database for clang tooling. The JSON compilation database is used in the clang project to provide information on how a single compilation unit is processed. With this, it is easy to re-run the compilation with alternate programs. Some build system natively supports the generation of JSON compilation database. For projects which does not use such build tool, Bear generates the JSON file during the build process. ``` 在 Ubuntu 下可以直接 Apt 安装 ```bash sudo apt install bear ``` Bear 的使用方式就是在原来的编译命令前加上 bear 命令即可,比如原来的编译命令为: ```bash make mrproper make defconfig make zImage -j4 ``` 在使用 Bear 时只要将命令改为: ```bash make mrproper make defconfig bear make zImage -j4 ``` 在编译完成后 Bear 将生成 compile_commands.json 文件。这个文件记录了工程是如何构建的,使用到了哪些源码文件,源码文件之间的包含关系,引用路径之类的。compile_commands.json 可以帮助 Clangd 构建符号关系索引库。 如果是交叉编译,需要将 compile_commands.json 中的“cc”全部替换为实际使用的交叉编译器,比如“arm-linux-gnueabihf-gcc”,然后保存。 如果项目下有 .cache 文件夹的话,需要删掉它。之后重新用 VSCode 打开源码目录,随便打开一个 .c 文件,Clangd 便自动开始索引文件了,索引文件会保存在 .cache 目录下。 由于内核源码较大,Clangd 将用几分钟的时间来建立索引。如果这个过程比较快,则说明配置没有生效。 如果一切顺利,就可以保存 VSCode 工程,以便下次使用。 ## 3. 外部参考资料 1. [VSCode 使用 Clangd](https://blog.csdn.net/m0_47329175/article/details/128677511) 2. [解决 clangd 设置 query-driver 后无法解析 include 路径](https://zhuanlan.zhihu.com/p/616838477) 3. [VSCode 使用 clangd 构建 Linux 驱动开发环境](https://blog.csdn.net/Telly_/article/details/134289358) 4. [使用 VSCode clangd 插件进行 linux 内核代码阅读和嵌入式开发](https://blog.csdn.net/m0_61738650/article/details/131529082) 5. [VSCode 使用技巧](https://www.cnblogs.com/zjutzz/p/15303480.html#35-%E5%87%BD%E6%95%B0%E6%97%A0%E6%B3%95%E8%B7%B3%E8%BD%AC-clangd-%E9%85%8D%E7%BD%AE-compile_commandsjson-%E8%B7%AF%E5%BE%84)