vscode/vim+clangd环境中实现正确索引交叉编译链中系统头文件路径
(本文假设读者早已对VSCode、LSP、clangd等相关知识有所了解,假如读者对相关内容仍未熟悉,建议先学习VSCode+LSP原理,再学习clangd插件的完整用法,clangd插件官方指导网站网站为:,强烈建议认真完整的学习该网站的所有内容!)
自从微软创造了V8引擎(演变出node.js,他是VSCode和coc.nvim插件的基础),谷歌创造了VSCode和LSP合同,苹果创造了clang和clangd,C/C++编辑器领域就发生了翻天覆地的变化linux系统的交叉开发的含义是什么?,先是VSCode+Remote-SSH+clangd插件通过LSP和clangd语言服务器实现了先进的“语法级”跳转+补全+高亮+句型静态解析+源码低格体验,后是vim世界通过移植VSCode源码实现重量级的coc.nvim插件(自此vim几乎可以和VSCode实现同步进化)。目前几乎所有的编辑器都在借助LSP生态在快速的塑造全新的功能特点。个人通过一段时间学习和配置linux格式化命令,目前发觉这套环境拿来查看Linux内核源码简直是神通常的存在。
clangd之所以可以完美的匹配Linux内核项目主要诱因是内核的Makefile维护的特别好的同时内核本身是一个完全自包含的项目,它对外界的依赖十分小(几乎所有的功能和函数库都在项目内部实现),因而只要形成正确的compile_commands.json就几乎可以实现100%确切的跳转等能力。
不过不仅内核,日常工作中接触更多的还是业务层相关的项目,作为一个嵌入式从业人员,99%的时间在和交叉编译链打交道。clangd配合PC环境的GCC项目基本上不怎样须要配置就可以表现的比较完美了,但哪些事情到了混乱的嵌入式领导都显得愈发折腾,clangd也不例外。clangd用于交叉编译项目的时侯一个显著的问题就是在默认配置下因为clangd不晓得交叉编译链的位置,因而也难以确切的晓得编译器自带的系统头文件位置,此时默认的动作是将/usr/include等GCC默认系统头文件路径作为搜索路径,带来问题有两个:一是源码文件中include的.h文件跳转不确切,二是因为系统头文件的定义差别,致使源码中好多地方的变量等定义都可能解析失败,最终造成在稍稍复杂点的项目中局部变量定义都可能跳转异常,这谁能忍!
目前解决该问题最简单的方式是通过给clangd传递–query-driver启动参数来通知clangd交叉编译器的位置,clangd在启动时会借助传递的交叉马桶参数手动解析出交叉编译链中所有系统头文件的路径(解析原理稍后剖析)并手动玩过编译惨数的更改。
VScode中实现项目级–query-driver参数的传递可以通过在项目根目录的“.vscode/settings.json”文件添加实现,配置类似如下:
{
"clangd.arguments": [
"--all-scopes-completion",
"--completion-style=detailed",
"--query-driver=/home/boddy/t7linux-auto/ext-toolchain/bin/arm-linux-gnueabi*"
]
}
其中/home/boddy/t7linux-auto/ext-toolchain/bin/arm-linux-gnueabi*表示按须要手动解析交叉编译链bin目录下所有arm-linux-gnueabi开头的交叉编译指令,假如你明晰的晓得项目使用的惟一交叉编译指令(如:arm-linux-gnueabi-g++)则也可以直接将–query-driver指定为/home/boddy/t7linux-auto/ext-toolchain/bin/arm-linux-gnueabi-g++"。
vim+coc.nvim环境若果没有用coc-clangd插件(直接在~/.vim/coc-settings.json全局配置中添加clangd作为c家族语言的languageserver)linux操作系统介绍,则对应项目级配置文件为项目根目录下的“.vim/coc-settings.json”,通过:CocLocalConfig可以直接创建并编辑linux系统的交叉开发的含义是什么?,配置类似如下:
{
"languageserver": {
"clangd": {
"args": [
"--all-scopes-completion",
"--completion-style=detailed",
"--query-driver=/opt/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf*"]
}
}
}
假如一个简单的–query-driver参数就可以彻底解决问题,那还算美好,可惜嵌入式领域总是饱含了波折。不幸的事情发生在使用清华微的/opt/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf这个交叉编译链上。现象很简单,–query-driver参数配置后基本无效,所有头文件还是手动跳转到/usr目录下。
通过查看clangd的输出日志,找到如下异常报错点:
报错的意思大约是说解析系统头文件扩充时起始标记未找到,成功配置的日志类似如下:
因为出错时,日志中出现了英文,凭着着敏锐的直觉,初步判定这可能和系统的英文环境有关,通过将Ubuntu系统的语言更改成中文后重新测,最终确定该问题是因为系统的英文环境造成。导致该问题原理解析如下:
clangd使用–query-driver参数的原理就是的通过配合compile_commands.json文件中交叉编译指令,通过手动执行类似arm-linux-gnueabi-g++-v命令来获得交叉编译器的基本信息。出错时出现的英文缘由是部份较高版本的交叉编译器支持输出时按照shell的语言环境输出对应的语言翻译结果信息,测试截图如下:
其中,第一个arm-linux-gnueabi-g++因为版本较低不支持系统语言匹配,因而总是输出中文信息,而第二个arm-linux-gnueabihf-g++因为版本较高支持了系统语言匹配,在英文环境下,部份低格的输出结果手动转换成了英文。通过临时更改语言配置,可以实现临时将输出结果修转换会英语。
目前clangd最新的版本为15.0,好多特点还处于研制阶段,很显著,–query-driver参数的解析目前没有考虑到多国语言环境的场景,默认只匹配英语输出。因而当指令结果出现英文时,就意外鸡鸡了。
该问题最简单的解决办法就是将操作系统的环境直接彻底更改为英语。不过直接将系统语言更改到英语有点暴力,并且面对一个满屏英语的系统,看习惯了英文的我还是十分不适应的,经过一下午的摸索,最终还是找到了一个相对可行的取代方式,现将该方式原理和用法记录如下:
通过对比–query-driver降低前后clangd的日志输出不难发觉,实际上–query-driver参数的目的就是通过找到交叉编译链并手动执行一些编译链的测试命令找到所有的系统头文件的所在路径,之后在句型树解析阶段将这种路径通过-isystem参数传递给clangd。对应解析截图如下:
截图中“1”的位置显著是解析获得了所有交叉编译链中的系统头文件检索路径,“2”位置则是在成功解析到路径后通过-isystem传递给了clangd,其中不仅传递所有的系统头文件检索路径外,还额外传递了–target和-driver-mode参数。
晓得原理后就可以想办法自己实现手动化。手动化思路为通过解析compile_commands.json手动获取正确的交叉编译器,通过编译器的一些测试指令获取当前项目使用的交叉编译器环境中的系统头文件路径集,最终手动将路径集批量添加-isystem头后导出到clangd的项目级配置文件中(项目根目录下的.clangd文件),另外我们还可顺便添加一下-driver-mode参数(–target参数其实作用不大)。
通过几个小时编撰测试,最终实现初版的手动化解析脚本(命名为gen_sys_inc.sh):
#!/bin/bash
compiler=`head -n 10 ./compile_commands.json | grep -Pzo ""arguments".*ns*".*n"|grep -av "arguments"|head -1|awk -F" '{print $2}'`
if [ "$compiler" = "" ];then
echo "compile_commands.json文件中没有找到有效的编译器参数"
return
fi
if [ "`echo $compiler|grep ++`" = "" ]; then
out="--driver-mode=gcc, "`$compiler -xc /dev/null -E -Wp,-v 2>&1 | sed -n 's,^ ,,p'|awk '{print "-isystem, "$0","}'`
else
out="--driver-mode=g++, "`$compiler -xc++ /dev/null -E -Wp,-v 2>&1 | sed -n 's,^ ,,p'|awk '{print "-isystem, "$0","}'`
fi
echo -e "CompileFlags:ntAdd: ["${out/%,}"]" > .clangd
使用方式:
将gen_sys_inc.sh脚本加入到path环境路径中去并赋于执行权限以便捷任意位置直接调用任意项目通过bear或则compiledb工具正确生成项目的compile_commands.json文件在compile_commands.json所在目录直接执行gen_sys_inc.sh脚本查看在当前目录手动生成的.clangd配置文件是否正确并打开项目C/C++源码测试跳转是否确切即可
注:因为.clangd文件是clangd自身的配置文件,和vim、vscode无关,因而采用gen_sys_inc.sh手动生成.clangd的形式配置项目额外带来了一个用处就是统一了vim和vscode在配置上的差别。