vscode是一个编辑器,可以调用各种插件来完成更多高级功能,clangd是一个代码解析工具,是clang的一个子项目。vscode中集成clangd以后,就可以精准的查看代码的调用情况,因为clangd对整个编译过程进行了跟踪(使用compile_commands.json文件实现),对于linux kernel这种复杂的项目非常适合,放弃source insight吧,那玩意儿没啥用,一个宏定义你能找出来几百个定义,鬼知道哪个是实际的定义来源。
下面按照步骤来搞一下:
1 安装vscode
这个自行搜索
2 在linux系统中安装cmake
安装clangd的时候有两种方法,一种是ubuntu中直接apt-get install,但是这种的clangd版本较低,一种是直接编译clangd的代码安装,编译代码用的cmake,所以还得装cmake,自行搜索,最好也编译代码安装,因为apt-get的cmake版本很低。参考如下文章:Linux编译安装cmake源码_回忆丿从前的博客-CSDN博客
3 在linux系统中安装clangd
这个估计可以使用apt-get install来安装,参考官网:Getting started (llvm.org)
Installing the
clangd
package will usually give you a slightly older version.
Try to install a packaged release (12.0):
sudo apt-get install clangd-12
If that’s not found, at least
clangd-9
or
clangd-8
should be available. Versions before 8 were part of the
clang-tools
package.
This will install clangd as
/usr/bin/clangd-12
. Make it the default
clangd
:
sudo update-alternatives --install /usr/bin/clangd clangd /usr/bin/clangd-12 100
但是我是直接下的代码编译后安装的,可以参考这个文章:ubuntu 安装 Clang/LLVM 15.0.4_llvm下载_525小白菜的博客-CSDN博客
这个文章里面编译代码安装了clang,因为clangd是clang的子项目,所以过程类似,clangd的安装过程参考这个:llvm-project/clang-tools-extra/clangd at main · llvm/llvm-project (github.com)
Building and testing clangd
For a minimal setup on building clangd:
- Clone the LLVM repo to
$LLVM_ROOT
.- Create a build directory, for example at
$LLVM_ROOT/build
.- Inside the build directory run:
cmake $LLVM_ROOT/llvm/ -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra"
.- We suggest building inRelease
mode as building DEBUG binaries requires considerably more resources. You can check Building LLVM with CMake documentation for more details about cmake flags.- In addition to that usingNinja
as a generator rather than defaultmake
is preferred. To do that consider passing-G Ninja
to cmake invocation.- Finally, you can turn on assertions via-DLLVM_ENABLE_ASSERTS=On
.- Afterwards you can build clangd with
cmake --build $LLVM_ROOT/build --target clangd
, similarly run tests by changing target tocheck-clangd
.
4 vscode中安装clangd插件
vscode中的clangd插件跟linux系统中的clangd是前后台程序的关系,vscode中的clangd插件其实是调用ubuntu的clangd程序的功能而已,说直白点,有点类似命令行调用,你看vscode中的clangd插件的配置,其实就是ubuntu中clangd程序的输入参数。
注意,如果你vscode中安装了“Microsoft C/C++”插件,请卸掉或者禁止掉。
参考:Getting started (llvm.org)中vscode部分
The official extension is vscode-clangd and can be installed from within VSCode.
Choose View –> Extensions, then search for “clangd”. (Make sure the Microsoft C/C++ extension is not installed).
After restarting, you should see red underlines underneath errors, and you should get rich code completions including e.g. function parameters.
vscode-clangd has excellent support for all clangd features, including:
- code completion
- diagnostics and fixes
- find declarations, references, and definitions
- find symbol in file (
Ctrl-P @foo
) or workspace (Ctrl-P #foo
)- hover and highlights
- code actions
Under the hood#
- Debug logs: when clangd is running, you should see “Clang Language Server” in the dropdown of the Output panel (View -> Output).
- Command-line flags: these can be passed in the
clangd.arguments
array in yoursettings.json
. (File -> Preferences -> Settings).- Alternate clangd binary: set the
clangd.path
string insettings.json
.
5 vscode中安装“remote - ssh”插件
这个是为了能远程登录到linux服务器或者虚拟机上去,因为你代码都是在linux上编译的,本地是windows,所以只能远程上去,这个插件怎么用的自行搜索吧。
6 编译代码并生成compile_commands.json
clangd能精准的浏览代码,依赖的是compile_commands.json这个文件,这个文件生成有好多方法,我用的方法是使用bear工具生成,安装方法:
sudo apt-get install bear
现在假设要编译一个uboot,具体的使用流程如下:
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
sudo bear -- make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12
上面的编译命令很简单,这就是普通的交叉编译流程,注意到最后编译的时候前面加了bear,这就是用来跟踪编译过程生成compile_commands.json
编译完成后,你就会看到目录下有这些文件了:
7 远程连接linux浏览代码
现在打开vscode,使用“remote - ssh”连到远程服务器上,打开对应的文件夹,打开vscode的output窗口,“ctrl+shift+p”执行下“clangd:restart language server”,
从第二个图可以看到,clangd运行正常对吧,这个时候选择一个c文件,看看效果呗
I[22:12:14.343] <-- shutdown(75)
I[22:12:14.343] --> reply:shutdown(75) 0 ms
I[22:12:14.348] <-- exit
I[22:12:14.348] LSP finished, exiting with status 0
I[22:12:14.357] clangd version 16.0.0
I[22:12:14.357] Features: linux
I[22:12:14.357] PID: 114268
I[22:12:14.357] Working directory: /home/imx6/work/uboot
I[22:12:14.357] argv[0]: /usr/local/bin/clangd
I[22:12:14.357] argv[1]: -compile-commands-dir=/home/imx6/work/uboot
I[22:12:14.357] argv[2]: --background-index
I[22:12:14.357] argv[3]: --completion-style=detailed
I[22:12:14.357] argv[4]: --header-insertion=never
I[22:12:14.357] argv[5]: -log=info
I[22:12:14.357] Starting LSP over stdin/stdout
I[22:12:14.357] <-- initialize(0)
I[22:12:14.358] --> reply:initialize(0) 0 ms
I[22:12:14.359] <-- initialized
I[22:14:37.129] <-- shutdown(1)
I[22:14:37.129] --> reply:shutdown(1) 0 ms
I[22:14:37.129] <-- exit
I[22:14:37.129] LSP finished, exiting with status 0
I[22:14:37.137] clangd version 16.0.0
I[22:14:37.138] Features: linux
I[22:14:37.138] PID: 115137
I[22:14:37.138] Working directory: /home/imx6/work/uboot
I[22:14:37.138] argv[0]: /usr/local/bin/clangd
I[22:14:37.138] argv[1]: -compile-commands-dir=/home/imx6/work/uboot
I[22:14:37.138] argv[2]: --background-index
I[22:14:37.138] argv[3]: --completion-style=detailed
I[22:14:37.138] argv[4]: --header-insertion=never
I[22:14:37.138] argv[5]: -log=info
I[22:14:37.138] Starting LSP over stdin/stdout
I[22:14:37.138] <-- initialize(0)
I[22:14:37.138] --> reply:initialize(0) 0 ms
I[22:14:37.139] <-- initialized
I[22:14:56.763] <-- textDocument/didOpen
I[22:14:56.763] <-- textDocument/documentSymbol(1)
I[22:14:56.763] <-- textDocument/documentHighlight(2)
I[22:14:56.763] <-- textDocument/semanticTokens/full(3)
I[22:14:56.763] <-- textDocument/codeAction(4)
I[22:14:56.766] Loaded compilation database from /home/imx6/work/uboot/compile_commands.json
I[22:14:56.767] --> window/workDoneProgress/create(0)
I[22:14:56.767] Enqueueing 257 commands for indexing
I[22:14:56.767] ASTWorker building file /home/imx6/work/uboot/common/autoboot.c version 1 with command
[/home/imx6/work/uboot]
/usr/local/bin/cc -c -Wp,-MD,common/.autoboot.o.d -nostdinc -isystem /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/4.9.4/include -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -mword-relocations -fno-pic -mno-unaligned-access -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -msoft-float -pipe -march=armv7-a -DKBUILD_STR(s)=#s -DKBUILD_BASENAME=KBUILD_STR(autoboot) -DKBUILD_MODNAME=KBUILD_STR(autoboot) -o common/autoboot.o -resource-dir=/usr/local/lib/clang/16 -- /home/imx6/work/uboot/common/autoboot.c
I[22:14:56.770] --> textDocument/clangd.fileStatus
E[22:14:56.770] Could not build a preamble for file /home/imx6/work/uboot/common/autoboot.c version 1: CreateTargetInfo() return null
E[22:14:56.770] error: unknown target CPU 'armv7-a'
I[22:14:56.770] --> workspace/semanticTokens/refresh(1)
I[22:14:56.771] <-- reply(0)
I[22:14:56.771] --> $/progress
I[22:14:56.771] --> $/progress
E[22:14:56.771] Failed to prepare a compiler instance: valid target CPU values are: nocona, core2, penryn, bonnell, atom, silvermont, slm, goldmont, goldmont-plus, tremont, nehalem, corei7, westmere, sandybridge, corei7-avx, ivybridge, core-avx-i, haswell, core-avx2, broadwell, skylake, skylake-avx512, skx, cascadelake, cooperlake, cannonlake, icelake-client, rocketlake, icelake-server, tigerlake, sapphirerapids, alderlake, raptorlake, meteorlake, sierraforest, grandridge, graniterapids, emeraldrapids, knl, knm, k8, athlon64, athlon-fx, opteron, k8-sse3, athlon64-sse3, opteron-sse3, amdfam10, barcelona, btver1, btver2, bdver1, bdver2, bdver3, bdver4, znver1, znver2, znver3, znver4, x86-64, x86-64-v2, x86-64-v3, x86-64-v4
I[22:14:56.771] --> textDocument/publishDiagnostics
I[22:14:56.771] --> reply:textDocument/documentSymbol(1) 7 ms, error: invalid AST
I[22:14:56.771] --> reply:textDocument/documentHighlight(2) 7 ms, error: invalid AST
I[22:14:56.771] --> reply:textDocument/semanticTokens/full(3) 7 ms, error: invalid AST
I[22:14:56.771] --> reply:textDocument/codeAction(4) 7 ms, error: invalid AST
I[22:14:56.771] --> textDocument/clangd.fileStatus
I[22:14:56.771] <-- reply(1)
[Error - 10:14:56 PM] Request textDocument/documentSymbol failed.
[object Object]
[Error - 10:14:56 PM] Request textDocument/documentHighlight failed.
[object Object]
[Error - 10:14:56 PM] Request textDocument/semanticTokens/full failed.
[object Object]
[Error - 10:14:56 PM] Request textDocument/codeAction failed.
[object Object]
解析文件的时候是有问题的,根本跑不起来,但是这不是clangd不行,是参数没配好,这里可以看到不支持这个“armv7-a”架构,那就是架构配置出问题了。
那么现在来配clangd的参数,参考:Configuration (llvm.org)
CompileFlags#
Affects how a source file is parsed.
CompileFlags: # Tweak the parse settings Add: [-xc++, -Wall] # treat all files as C++, enable more warnings Remove: -W* # strip all other warning-related flags Compiler: clang++ # Change argv[0] of compile flags to `clang++`
clangd emulates how clang would interpret a file. By default, it behaves roughly as
clang $FILENAME
, but real projects usually require setting the include path (with the
-I
flag), defining preprocessor symbols, configuring warnings etc.
Often, a compilation database specifies these compile commands. clangd searches for
compile_commands.json
in parents of the source file.
This section modifies how the compile command is constructed.
所以,配置流程就是:
1 在代码目录下新建文件“.clangd”
2 在其中假如刚才的架构配置
CompileFlags: # Tweak the parse settings
Add: [--target=arm] # treat all files as C++, enable more warnings
vscode中“ctrl+shift+p”执行下“clangd:restart language server”,再次进入一个c文件,你会发现,可以了。
现在可以愉快的阅读内核代码了。
版权归原作者 oushaojun2 所有, 如有侵权,请联系我们删除。