前言:在编译一些非标准linux内核时,常会出现一些错误导致编译中止。这其中的大部分都能通过根据编译器报出的错误定位来查阅源码、找到相关的依赖配置,然后修正配置状态来解决。但也有时候从依赖逻辑中无法发现问题所在,这就不得不把整个内核配置都倒腾一遍,这将花费大量的时间精力。本文便是在倒腾过程中发现的一些能够提高效率的小技巧的总结。
关键词:linux,内核编译,错误定位
适用场景:
- 有一份能够正常编译不报错的配置文件;
- 通过查阅源码实在找不到造成问题的内核配置项;
- 能够确定错误是由内核配置引起的,而不是其它诸如环境配置等问题导致的。
(以上条件满足越多越合适)
1 简单认识两个内核源码里的文件
-
include/generated/autoconf.h:
该文件由.confg文件转换而成。在使用make menuconfig修改配置后.config文件会被修改,但仅仅这样是无法影响到内核源码的。于是在内核编译的时候会将.config文件中的配置项转换为autoconf.h文件里对应的宏定义,如此便可供内核里的C源码使用。
-
scripts/Kbuild.include:
该文件被顶层的Makefile引用,在编译时会被执行。其中有几条命令控制着编译的具体命令,但是命令前加了@
符合,导致编译命令本身被屏蔽,只显示结果。将@
符合去掉,就可以显示命令本身的内容。
顶层Makefile对Kbuild.include文件的引用:
Kbuild.include文件:
2 基本思路
- 对比正常编译的autoconf.h和编译出错的autoconf.h文件,找出差异项,将搜寻范围缩小至差异项;
- 参照差异项使用二分法批量修改autoconf.h文件,可在较少次数内定位到目标配置项;
- 去掉Kbuild.include文件中
@set -e
前的@
,显示编译命令的具体内容,由此可获得导致错误的命令; - 直接使用导致错误的命令来编译验证修改后的配置,可缩短验证过程的时间。
3 示例
-
下图是一个is deprecated错误,在将该错误代码处相关的几个文件来来回回看了几遍后,依然没有找出能够修正错误的配置项:
-
修改scripts/Kbuild.include文件,释放出命令的具体内容:
-
再次编译,可以看到编译的具体命令了:
-
试一下,确实是这条命令报的错:
-
将autoconf.h文件备份一份,以防后续修改出错;然后就可以比较编译正常的autocof.h文件与当前导致错误的autoconf.h文件:
-
总共约2000条配置,左边是可以正常编译的,右边是有问题的:(实际上如果用beyond compare来比较可以只显示差异行,只需要从1000多条差异项中筛选即可,奈何这里用的diffuse工具无法只显示差异项)
-
使用二分法筛选,2000条理论上筛选11遍即可找出导致错误的配置;实际为了保险起见可能需要把二分法筛选淘汰的那一半也验证一下,因为要防止导致错误的配置项不止一条的情况:
先使用可正常编译的配置文件的前1000项替换有问题的配置文件的对应配置:
虽然报了其它错误,但没有报那个is deprecated的错误。 -
可以判断错误配置项在前1000项里,还是使用剩余的后1000多项验证一下:
也报了一堆其它错误,但同时也出现了之前的错误,说明后面的1000多项并不影响这个错误,验证了之前的判断。
(后面是繁琐的调试过程)
-
这时范围缩小到前1000项,再分:
前512项:
后半部分:
前512项没出现,后半部分出现了,可以再把范围缩小到前512项。 -
前244项:
后半部分:
前244项依然出现,后半部分正常,可以判断在后半部分。 -
245-384项:出现目标错误
后半部分(385-512):没出现
可以判断在后半部分。 -
385-455:
456-512:
两个都出现错误?后来反复验证了几遍确实是这样。 -
在455项和456项之间,有一个配置项左边能正常编译的文件里没有,但是右边的文件有,所以刚才两次覆盖恰好都没有覆盖到它,猜测这个可能就是要找的配置项了:
-
去掉该配置项:
编译正常,没想到提前解决了。 -
直接在make menuconfig里关闭CONFIG_ENABLE_WARN_DEPRECATED配置项,然后make编译:
又报了新的错误,但至少那个is deprecated的错误是解决了。
最后原因竟然是不能开启deprecated警告,这就是非标准内核的魅力吧aaaa。
-END-