【技巧】一种提高 [ 定位Linux内核编译错误 ] 效率的方法

前言:在编译一些非标准linux内核时,常会出现一些错误导致编译中止。这其中的大部分都能通过根据编译器报出的错误定位来查阅源码、找到相关的依赖配置,然后修正配置状态来解决。但也有时候从依赖逻辑中无法发现问题所在,这就不得不把整个内核配置都倒腾一遍,这将花费大量的时间精力。本文便是在倒腾过程中发现的一些能够提高效率的小技巧的总结。

关键词:linux,内核编译,错误定位

适用场景:

  • 有一份能够正常编译不报错的配置文件;
  • 通过查阅源码实在找不到造成问题的内核配置项;
  • 能够确定错误是由内核配置引起的,而不是其它诸如环境配置等问题导致的。

(以上条件满足越多越合适)

1 简单认识两个内核源码里的文件

  1. include/generated/autoconf.h:
    该文件由.confg文件转换而成。在使用make menuconfig修改配置后.config文件会被修改,但仅仅这样是无法影响到内核源码的。于是在内核编译的时候会将.config文件中的配置项转换为autoconf.h文件里对应的宏定义,如此便可供内核里的C源码使用。
    autoconf.h文件

  2. scripts/Kbuild.include:
    该文件被顶层的Makefile引用,在编译时会被执行。其中有几条命令控制着编译的具体命令,但是命令前加了@符合,导致编译命令本身被屏蔽,只显示结果。将@符合去掉,就可以显示命令本身的内容。
    顶层Makefile对Kbuild.include文件的引用:
    顶层Makefile对Kbuild.include文件的引用
    Kbuild.include文件:
    scritpts/Kbuild.include中的控制编译具体命令的命令

2 基本思路

  1. 对比正常编译的autoconf.h和编译出错的autoconf.h文件,找出差异项,将搜寻范围缩小至差异项;
  2. 参照差异项使用二分法批量修改autoconf.h文件,可在较少次数内定位到目标配置项;
  3. 去掉Kbuild.include文件中@set -e前的@,显示编译命令的具体内容,由此可获得导致错误的命令;
  4. 直接使用导致错误的命令来编译验证修改后的配置,可缩短验证过程的时间。

3 示例

  1. 下图是一个is deprecated错误,在将该错误代码处相关的几个文件来来回回看了几遍后,依然没有找出能够修正错误的配置项:
    一个is deprecated error

  2. 修改scripts/Kbuild.include文件,释放出命令的具体内容:
    修改

  3. 再次编译,可以看到编译的具体命令了:
    显示具体命令的编译方式

  4. 试一下,确实是这条命令报的错:
    具体命令编译时报错

  5. 将autoconf.h文件备份一份,以防后续修改出错;然后就可以比较编译正常的autocof.h文件与当前导致错误的autoconf.h文件:
    比较autoconf.h文件

  6. 总共约2000条配置,左边是可以正常编译的,右边是有问题的:(实际上如果用beyond compare来比较可以只显示差异行,只需要从1000多条差异项中筛选即可,奈何这里用的diffuse工具无法只显示差异项)
    左边是可以正常编译的,右边是有问题的

  7. 使用二分法筛选,2000条理论上筛选11遍即可找出导致错误的配置;实际为了保险起见可能需要把二分法筛选淘汰的那一半也验证一下,因为要防止导致错误的配置项不止一条的情况:
    先使用可正常编译的配置文件的前1000项替换有问题的配置文件的对应配置:
    替换前1000项
    虽然报了其它错误,但没有报那个is deprecated的错误。

  8. 可以判断错误配置项在前1000项里,还是使用剩余的后1000多项验证一下:


    也报了一堆其它错误,但同时也出现了之前的错误,说明后面的1000多项并不影响这个错误,验证了之前的判断。

(后面是繁琐的调试过程)

  1. 这时范围缩小到前1000项,再分:
    前512项:

    后半部分:


    前512项没出现,后半部分出现了,可以再把范围缩小到前512项。

  2. 前244项:

    后半部分:

    前244项依然出现,后半部分正常,可以判断在后半部分。

  3. 245-384项:出现目标错误

    后半部分(385-512):没出现

    可以判断在后半部分。

  4. 385-455:

    456-512:

    两个都出现错误?后来反复验证了几遍确实是这样。

  5. 在455项和456项之间,有一个配置项左边能正常编译的文件里没有,但是右边的文件有,所以刚才两次覆盖恰好都没有覆盖到它,猜测这个可能就是要找的配置项了:

  6. 去掉该配置项:

    编译正常,没想到提前解决了。

  7. 直接在make menuconfig里关闭CONFIG_ENABLE_WARN_DEPRECATED配置项,然后make编译:


    又报了新的错误,但至少那个is deprecated的错误是解决了。

最后原因竟然是不能开启deprecated警告,这就是非标准内核的魅力吧aaaa。
-END-

猜你喜欢

转载自www.cnblogs.com/DoughMonster/p/13378791.html