1
|
builtin
-target :=
$(obj)
/built-in
.o
|
1
2
|
$(builtin-target)
:
$(obj-y)
FORCE
$(
call
if_changed,link_o_target)
|
1
2
|
kbuild-
file
:= $(
if
$(
wildcard
$(kbuild-dir)
/Kbuild
),
$(kbuild-dir)
/Kbuild
,
$(kbuild-dir)
/Makefile
)
include
$(kbuild-file)
|
比如在 init 目录下可以看到 obj-y 的一行定义:
1
|
obj-y := main.o version.o mounts.o
|
1
2
3
|
$(obj)
/%.o:
$(src)
/%.c FORCE
$(
call
cmd,force_checksrc)
$(
call
if_changed_rule,cc_o_c)
|
1
2
3
|
if_changed_rule = $(
if
$(
strip
$(any-prereq)
$(arg-check)
), \
@
set
-e; \
$(rule_
$(1)
))
|
1
2
3
4
|
arg-check = $(
strip
$(
filter-out
$(cmd_
$(1)
), $(cmd_
$@
)) \
$(
filter-out
$(cmd_
$@
), $(cmd_
$(1)
)) )
... ...
any-prereq = $(
filter-out
$(PHONY)
,
$?
) $(
filter-out
$(PHONY)
$(
wildcard
$^
),
$^
)
|
$@ 表示目标文件,从上面叙述可知,它就是 $(obj)/%.o 。比如编译 init/main.o ,那么 $(cmd_$@) 就是表示 $(cmd_init/main.o),而在 init/.main.o.cmd 文件中我们看到了 cmd_init/main.o 用来保存着上次编译的参数。在 arg-check 中,首先使用 $(filter-out $(cmd_$(1)), $(cmd_$@)) 将上一次的编译参数中过略掉本次要编译的参数,再用 $(filter-out $(cmd_$@), $(cmd_$(1))) 将本次的编译参数中过滤掉上一次的编译参数。正反过滤的原因是,filter-out 函数在过滤时,如果第 2 个参数是第 1 个参数的子集或者是相同,那么返回空;所以,在第 1 次过滤时如果返回为空,那么 cmd_$@ 可能是等于 cmd_$(1) 的,也可能是它的子集,所以只有当再次反过来做过滤时发现返回为空,那么才能判断两次编译的参数是相等的,否则是不等的。如果返回结果不为空,说明编译参数发生了变化,那么就会执行 $(rule_cc_o_c) 。
if_changed 定义在 scripts/Kbuild.include 中:
1
2
3
4
5
6
|
# 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)
); \
echo
'cmd_$@ := $(make-cmd)'
>
$(dot-target)
.cmd)
|
1
2
|
.tmp_vmlinux2:
$(vmlinux-lds)
$(vmlinux-all)
.tmp_kallsyms1.o FORCE
$(
call
if_changed,vmlinux__)
|
1
2
3
4
5
6
7
8
9
|
# read all saved command lines
targets := $(
wildcard
$(
sort
$(targets)
))
cmd_files := $(
wildcard
.*.cmd $(
foreach
f,
$(targets)
,$(
dir
$(f)
).$(notdir
$(f)
).cmd))
ifneq
(
$(cmd_files)
,)
$(cmd_files)
: ;
# Do not try to update included dependency files
include
$(cmd_files)
endif
|