#创作者激励#由一个编译参数引发的gn构建依赖图谱查询 原创 精华
【本文正在参加2023年第一期优质创作者激励计划】
目录
起因
事情的起因是这样子的,在给学生上课的时候,想演示一下kv存储(小熊派nano开发板),代码版本master
,结果发现编译竟然出错了,错误提示如下:
显示的是在链接阶段没有找到如opendir,closedir等符号,这显然就是kv_store库编译有问题
原因及措施
经过几分钟的查找,最后发现是kv_store库的gn文件里面默认给了这个参数:
这个参数一加,我们kv的编译就会使用posix相关的接口去实现,而在3861里面应该是没有实现posix相关的文件接口,所以导致链接的时候出现opendir等等通不过,那么将这个参数置false再编译试试看:
不出意外的编译成功了,说明问题出在这里.
隐患
你以为问题到这里就完了吗,当然,如果只是以解决问题作为目的,我们当前确实已经达到目的了.
作为一个自律的工程师,我们知道:我们在做应用的时候不应该做侵入式修改,什么是侵入式修改呢:
一句话概括就是,你的代码需要依赖框架的代码,如果把框架拿掉或者换一个框架,就需要重新修改代码。
也就是说:kv是openharmony里面的一个组件,我们使用openharmony的代码框架的时候如果碰到问题,是不能通过侵入式修改达到目的的,因为这样会破坏原有的代码逻辑,假如后面如果有其他项目要使用这个代码的话,就可能会出现问题,有时候甚至会是灾难性的后果.
而且,侵入式修改有一个问题是:如果sdk或框架升级,往往意味着要在新的sdk或者框架上进行修改,当这种修改多起来的话工作量也是非常大的,如果没有准确的文档进行check,往往不能修改成功.
非侵入修改
那么不能用侵入式修改,又想达到正确编译kv库的目的,要怎么做呢,有一个办法是使用gn的args,使用方法如下:
hb build -f --gn-args enable_ohos_utils_native_lite_kv_store_use_posix_kv_api=false
这种方法会强制覆盖代码中的已声明的变量,同样能达到编译通过的办法.
那么这种方法有什么缺点吗:当然有,就是每次编译都需要带上长长的一串东西,且不说记不记得住吧,使用起来也是非常的不方便.
另外一种方法就是:在vendor对应的目录下的config.json里,对应的组件内feature添加对应的参数声明,这一种方式,在产品的readme文档里也有介绍,比如:
比如我们现在是在编译bearpi_hm_nano,那么我们只需要在vendor/bearpi/bearpi_hm_nano/config.json
里面编辑,把kv_store库添加对应的参数即可,这里不知道是bug还是gn的原理就是这样,我们不需要找到kv_store真正的库声明位置,而是随便一个地方加上"enable_ohos_utils_native_lite_kv_store_use_posix_kv_api=false"
就可以正常编译通过了,比如:
这样再编译就成功了.
探究一下原理,在gn进行build的时候,会在out目录下生成一个args.gn
文件,这个文件里保存了所有需要用到的args,如:
这里的args都是顺序排列的,在gn进行构建的时候会读取里面所有的参数.
另外一个问题
kv_store是什么时候调用并编译的?
到这里问题应该就解决了,但是刚刚我发现另外一个问题,在添加feature
的时候我们并没有找到kv_store
在config.json
文件里显示声明组件,那么到底是在什么时候kv_store
参与编译了呢?
这里是config.json的内容:
找了一圈,并没有找到kv相关的库,看来kv_store是由别的子系统或组件库依赖的
那是由谁依赖的呢?
#查找依赖kv_store的库或组件
首先,一个库被依赖通常会写在gn的deps列表内,比如这种:
如果还不明白,建议找几篇gn相关的文章看看就懂了
现在的办法就是一层一层的找到是谁调用的kv_store
库,回到之前编译出错的地方:
可以看到有一个名为utils_kv_store
的lib文件,先找一下:
然后再去找由谁依赖了utils_kv_store
,
现在问题出来了,openharmony里面这么多代码,如果每一个库都要这样不停的搜索相关字才能找到最终依赖的地方,效率低不说,还容易出错,而且很容易跟着就跟丢了,这是因为人的记忆力毕竟有限,函数调用太多层就会丢失路径,这也就是为什么人类下棋永远下不过电脑.
请出神器
这时候就轮到了我们gn desc这个神器出厂了,我们先来看一下效果,这是依靠gn desc生成的依赖树信息:
看起来有点乱,没关系,主要我们根据这个树状结构找到我们所有的依赖,有了这样的依赖关系之后,我们如果想要查找某两个模块的关系就非常简单了,以我们刚刚说了kv_store
为例:
可以看到很轻松就找到了kv_store
是怎么被一层一层依赖的了,而且通过关系图可以得知kv_store
竟然是由device_auth
引入的,那么这个工具的意义就在于:有了依赖树,以后出现依赖相关的问题都可以通过它快速分析并定位问题了.
看到这里是不是好心动,是不是想学习一下怎么用呢?
只需要在命令行输入gn help desc
就能得知用法了:
其中 <out_dir>就是我们编译的输出目录
<label or pattern> 可以是一个目标标签,配置标签,或者一个匹配模式标签。只有匹配成功的才会显示。
<what to show> 包括如下(如果不指定,默认显示):
all_dependent_configs
allow_circular_includes_from
arflags [–blame] args
cflags [–blame]
cflags_c [–blame]
cflags_cc [–blame]
check_includes
configs [–tree] (see below)
data_keys
defines [–blame]
depfile
deps [–all] [–tree] (see below)
framework_dirs
frameworks
include_dirs [–blame]
inputs ldflags [–blame]
lib_dirs libs
metadata
output_conversion
outputs
public_configs
public
rebase
script
sources
testonly
visibility
walk_keys
weak_frameworks
runtime_deps
[–format=json] 以JSON的格式输出。
根据以上提示,我们制作查询语句:
root@346a62050f11:/home/openharmony# gn desc out/bearpi_hm_nano/bearpi_hm_nano //out/bearpi_hm_nano/bearpi_hm_nano/build_configs/device_bearpi_hm_nano/device_bearpi_hm_nano:device_bearpi_hm_nano --tree
,即可得到依赖树等内容.
总结
本篇真实记录了一次出现问题,排查问题,解决问题并进行深层次思考的过程,最后通过不断的查找资料,找到了一个可以瞬间生成依赖树的强大工具,为以后解决问题提供了一种思路.
希望各位热爱学习的朋友,能够沉心静气,耐住寂寞,永不言弃,因为只有经过这样的过程,技术才能得到精进,然后总结出自己的学习套路,学习有一万种方法,最重要的是行动.
大佬厉害
老师技术过硬能在现场快速解决问题
侵入式修改使代码代码更耦合了
已经将文章分享给敲代码的同事了
记得点赞支持啊哈哈
我以前还手动整理过小型系统foundation进程的依赖关系,早知道有这个神器,效率不知道高了多少倍!!
哈哈,那不一样,用自动化工具是为了快速定位问题,手动整理学的更扎实
才知道作者是老师
偶尔讲讲课,但确实在教育岗
学校老师就经常说看问题不能看表面,真正弄懂问题才能有收获
改框架确实风险比较大