背景: 在开发大型工程例如Android或Linux时若我们使用vscode搭配官方的C/C++插件使用发现,经常很多代码都无法跳转,代码补全功能几乎是废的,通过网友以及同事身边了解之后发现vscode+clangd可以实现代码任意跳转补全等功能,因此本文通过讲解如何配置clangd相关环境实现高效开发。
首先自然就是卸载vscode官方提供的C/C++因为功能和clangd会有冲突,建议直接删除(禁用)
准备所需插件:主要有两个clangd以及SSH(按需求安装)
1.clangd
2.SSH(使用远程服务器配置)
参考:vscode连接SSH远程服务器(详细版)
安装好clangd插件之后只是一个套壳现在代码是不能跳转的,需要通过clangd language的支持来完成跳转,clangd language的下载方式有两种方法
方式一:
下载好之后任意打开一个C/CPP文件,vscode下方会出现弹窗直接install即可(若网络原因或其他原因这里一直下载不出来请参考方式二)
方式二:
从GitHub上下载clangd-language
选择最新的版本即可,开发环境是linux选择linux即可,博主这里选用的就是linux,其他系统同理。
将下载好的clangd解压到任意一个path下,如下
cd /home/zly/tools/
unzip clangd_16.0.2.zip
在vscode上按住ctrl+,进入配置选项,如下在clangd中填写我们下载好的language的path。
clangd准备工作在上述,虽然已经基本完成,但是如果打开工程代码还是会发现代码还是不能够任意跳转,这是因为clangd查询不到对应的工程头文件,因此需要生成compile_commands.json,使用compile_commands.json文件来生成索引文件,这样当我们点击某个函数时可以飞快跳转到它定义的地方。
compile_commands.json文件中记录的是每个文件的编译选项,样式如下:
{
"arguments": [
"/home/zly/work/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc",
"-c",
"-Wp,-MD,cmd/.test.o.d",
"-nostdinc",
"-isystem",
"/home/zly/work/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/../lib/gcc/arm-linux-gnueabihf/6.3.1/include",
"-Iinclude",
"-I./arch/arm/include",
"-include",
"./include/linux/kconfig.h",
"-D__KERNEL__",
"-D__UBOOT__",
"-Wall",
"-Wstrict-prototypes",
"-Wno-format-security",
"-fno-builtin",
"-ffreestanding",
"-fshort-wchar",
"-Werror",
"-Os",
"-fno-stack-protector",
"-fno-delete-null-pointer-checks",
"-g",
"-fstack-usage",
"-Wno-format-nonliteral",
"-Werror=date-time",
"-D__ARM__",
"-Wa,-mimplicit-it=always",
"-mthumb",
"-mthumb-interwork",
"-mabi=aapcs-linux",
"-mword-relocations",
"-fno-pic",
"-mno-unaligned-access",
"-mabi=aapcs-linux",
"-funwind-tables",
"-ffunction-sections",
"-fdata-sections",
"-fno-common",
"-ffixed-r9",
"-msoft-float",
"-pipe",
"-march=armv7-a",
"-D__LINUX_ARM_ARCH__=7",
"-I./arch/arm/mach-rockchip/include",
"-DKBUILD_STR(s)=#s",
"-DKBUILD_BASENAME=KBUILD_STR(test)",
"-DKBUILD_MODNAME=KBUILD_STR(test)",
"-o",
"cmd/test.o",
"cmd/test.c"
],
"directory": "/home/zly/work/u-boot",
"file": "cmd/test.c"
},
compile_commands.json(也就是compilationdatabase,具体详细规范可以参考clangd说明)给clangd传递这些参数。
接下来通过kernel以及Android工程来分别生成compile_commands.json,
一、kernel中生成compile_commands.json
方法a:(注意!进行以下操作前需要确保工程提前被编译过)
kernel中自带了scripts/clang-tools/gen_compile_commands.py可以直接生成(低内核版本没有该脚本,可以从网上下载一个)
zly@zly-machine:~/work$ ./build.sh kernel
........................................
./kernel/arch/arm/lib/.memchr.o.cmd
./kernel/arch/arm/lib/.lib1funcs.o.cmd
./kernel/arch/arm/lib/.call_with_stack.o.cmd
........................................
zly@zly-machine:~/work/kernel$ python3 ./scripts/clang-tools/gen_compile_commands.py
方法b:(注意工程要没有编译过!若编译过make clean一下)
通过使用bear来生成:Bear 是一个用于生成编译器的工具,它可以将编译器前端的源代码转换成抽象语法树(AST)并输出到一个JSON文件中。
zly@zly-machine:~$ sudo apt-get install bear
bear make [其他make本身的参数]
它会记录make过程编译文件时用到的命令。
所以我们编译内核的目的是生成compile_commands.json,执行如下命令:
zly@zly-machine:~/work$ bear ./build.sh kernel
同样会生成compile_commands.json,将该json,cp到我们对应的工程下即可。
二、Android中生成compile_commands.json
安卓和kernel其实是同理的,但是安卓工程更加庞大,在安卓7之后基本工程直接使用ninja来进行编译构建的,因此我们可以直接通过ninjia快速构建同步生成对应的compile_commands.json.
ninja提供了一个工具(-t commands)可以生成特点目标的编译命令:
ninja -f combined-hal.ninja -t commands MODULES-IN-vendor-rockchip > commands.txt
使用gen_compdb:
gen_compdb: -c -i commands.txt -o compile_commands.json
cp compile_commands.json ./work
综上将compile_commands.json生成好并且放到相关工程中即可,正式使用了,使用前,在vscode重启下clangd:ctrl+shift+p
之后就可以实现代码的任意跳转了~,clangd功能十分强大!不单单只有代码跳转那么简单,还可以为代码提供补全、错误提示、跳转、导航等功能。
clangd是一个C/C++语言的基于LSP的语言服务实现,可以为代码提供补全、错误提示、跳转、导航等功能。
代码补全:
转到定义、引用、实现:
快速定位:(ctrl+shift+o、ctrl+T)
对整个文件(Shitft+Alt+F),选中区域格式化(Ctrl+K Ctrl+F)