编译Linux内核时使用较高版本make
导致每次均全量编译的问题
1、前言
标题有点长,但没办法,现象就是这么个现象,少几个字都不足以完整描述问题。
2、背景
最近想转嵌入式驱动,搞了块板子,并在B站看了两个星期的配套教程视频后,
开始转入实战阶段。开头没什么大障碍,解决几个编译报错之后,
内核镜像就编译出来了。唯一令人困惑的是,每次都是全量编译,即使一个文件都没改,
make xx_defcong
、make menuconfig
、make clean
之类的更是没执行过。
在网上搜索一番无果之后,本着无谓的时间就算一秒也不能浪费的心态,
以及难以抑制的好奇心,自行动手开启了抽丝剥茧之旅。
3、过程
3.1 首先怀疑Makefile
首先是怀疑开发板商家是不是后来修改了Makefile,或自行添加了某些脚本, 以至于每次都在初始化阶段更新了某些文件。虽然大改Makefile的概率很小, 但确认一下还是好的,于是下了一份纯净版的Linux内核源码, 与开发板内核源码分别解压到两个目录,再用命令把所有Makefile都找出来:
for i in original custom
do
find $i/ -iname "*Makefile*" -o -iname "*.mk" | sort > $i/mks.txt
done
再对比一下两份Makefile清单有哪些差异:
diff original/mks.txt custom/mks.txt
一方比另一方多出的Makefile只有寥寥几个,可手动打开肉眼观察,
都是简单的添加*.o
文件,肯定不会对编译产生影响。
接下来,逐个对比Makefile的差异——当然不可能手动打开肉眼对比啦。
可以用Beyond Compare
,设置成只显示差异的模式以及只过滤出Makefile来对比,
不过我还是嫌麻烦,就用了最擅长的命令行来解决:
while read i
do
printf ">>> ${i}\n";
diff original/$i custom/$i || printf "\n\n\n";
done < original/mks.txt
果然发现商家版的一个Makefile里面调用了它自家的一个小程序做了一些初始化, 以为找到了问题根源。谁知把这个操作屏蔽之后,没有任何效果,每次依旧全量编译, 我不禁开始思考人生……
3.2 大胆点,怀疑make程序
既然Makefile找不出问题,再结合Sherlock Holmes
的一句名言:
When you have eliminated the impossibles,
whatever remains, however improbable,
must be the truth.
虽然尚未穷尽所有的“不可能”,但实操可不必像理论那般严谨,更多依靠的是经验、直觉, 向着概率最大的方向探索。何况,之前看教程视频时注意到里面用的是Ubuntu 16.04, 商家提供的资料链接里则为18.04,而我平时老旧笔记本用的是20.04,台式机用22.04, 之前还觉得这不会造成什么问题,现在看来倒也未必。 因为,不同版本操作系统的软件包管理器提供的make程序版本不一样, 进而推知其解析Makefile目标依赖关系的逻辑也可能不一样, 何况Linux内核Makefile又包含复杂的逻辑,两者交织一起, 导致高低版本分别出现全量编译和增量编译的差异,不是没有可能。综上所述, 怀疑make版本是问题根源的猜想,很合情合理,只剩下验证而已。
3.3 有怀疑就验证,能想更要能做
根据前述猜想,很容易得出解决思路:确定Ubuntu 16.04或18.04的make版本, 再下载其源码进行编译安装,最后利用新make来编译内核即可。但我不想把个人环境搞乱, 何况现在又有docker之类的容器环境,安全又好用,所以不必多想, 直接用docker分别构造了16.04和18.04的容器,使用之前相同的一套操作, 反复多次进行了编译,最终确实验证了是make版本导致了全量或增量编译的问题根源。 以下是多个环境的make版本:
16.04: 4.1-6
18.04: 4.1-9.1build1
20.04: 4.2.1-1.2
22.04: 4.3-4.1build1
注意,以上结果是使用apt list make
得到的,若使用make -v
只会得到4.x
大版本号。
另外,在较低版本Ubuntu编译内核时,会因为32位库兼容的问题, 会报缺失一些组件缺失或XX程序XX库找不到文件或目录的错误,不在本文的讨论范围, 仅给出解决问题的命令以供参考:
sudo apt install lib32ncurses5 lib32z1 lib32stdc++6
4、总结
-
操作系统版本影响make程序版本,而后者又影响解析Makefile目标依赖关系的逻辑, 加上Linux内核Makefile逻辑复杂,容易解析不准而导致每次均全量编译。
-
Makefile的哪部分、哪些写法触发这种Bug(暂定为Bug),暂无时间研究, 要么留待以后探究,要么后续的make解决这个Bug。