这篇文章是内核编译探索的重要知识点汇总,类似一个工具,列举了我所见到的一些target, rule. 以此希望对内核编译更进一步了解。
然而如果没有实际内核编译的经验,可能会觉得比较枯燥。建议从这个内核编译探索系列开始阅读。
稍微谈一点架构
文章写到一大半,发现可以来谈谈“架构”了。把这部分放到开始,或许会对大家理解有点帮助。
整个内核代码从make的角度来看,可能是这样的。
+-- Makefile
|
+--+ init
| |
| +-- Makefile
|
+--+ fs
| |
| +-- Makefile
| |
| +-+ ext4
| |
| +-- Makefile
|
+--+ kernel
| |
| +-- Makefile
| |
| +-+ sched
| |
| +-- Makefile
|
+--
其实说白了就是每个层次目录中的Makefile中定义好相应的目标,如果有下一层,则进入到下一层继续编译。而这个过程中比较重要的文件是Makefile.build.
[更正]: “进入下一层”的表达有误。 在整个内核编译过程中,当前目录都是内核源码树的根目录。对不同目标,不同路径下的目标的编译,是通过obj变量做到的。这一点需要细看Makefile.build文件。
据说make中多线程同时编译,就是要依靠这么进入下一层来实现的。
rules
if_changed_xxx
这个规则实在是太重要,曝光率也是超高。
一般用法是这样的
$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
$(call if_changed,image)
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
那来展开一下该定义在scripts/Kbuild.include中
###
# if_changed - execute command if any prerequisite is newer than
# target, or command line has changed
# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
# including used config symbols
# if_changed_rule - as if_changed but execute rule instead
# See Documentation/kbuild/makefiles.txt for more info
恩,原来有兄弟三个呢。先来看看大哥的样子
# Execute command if command has changed or prerequisite(s) are updated.
#
if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
@set -e; \
$(echo-cmd) $(cmd_$(1)); \
printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
第一眼看这么长,其实我的内心是有点抵触的。一层层来看吧
首先这是个if语句, 当条件为真,则执行一个,若为假,则执行另一个。这么来看,逐个击破~
判断条件
$(strip $(any-prereq) $(arg-check))
意思就是所有依赖条件和arg-check字符串中如果有字符串,那么就会执行相关命令。
有没有新的依赖
# Find any prerequisites that is newer than target or that does not exist.
# PHONY targets skipped in both cases.
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
人注释写得真到位,一个表示比目标更新的依赖,一个表示还不存在的依赖。
先看看两个自动变量,
- $? The names of all the prerequisites that are newer than the target
- $^ The names of all the prerequisites
第一个太明显,第二个要看一下wildcard函数的定义了,
This string, used anywhere in a makefile, is replaced by a
space-separated list of names of existing files that match one of the
given file name patterns
恩,就是用来找到现在已经有的文件的。那结合定义,就是先找到依赖中已经存在的文件,然后从所有依赖中去掉。那不就剩下还没有生成的依赖了么。
有没有arg-check变化
# Check if both arguments are the same including their order. Result is empty
# string if equal. User may override this check using make KBUILD_NOCMDDEP=1
arg-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \
$(subst $(space),$(space_escape),$(