if_changed_rule/cc_o_c/any-prereq/arg-check|Makefile - 曲径通幽 - Powered by phpwind

查看完整版本: [-- if_changed_rule/cc_o_c/any-prereq/arg-check --]

曲径通幽 -> Makefile -> if_changed_rule/cc_o_c/any-prereq/arg-check [打印本页] | 登录 -> 注册 -> 回复主题 -> 发表主题

beyes | 2011-07-01 15:01

# if_changed_rule/cc_o_c/any-prereq/arg-check

Makefile 对应内核版本：2.6.35.13
在 scripts/Makefile.build 的 86 行看到 builtin-target 的定义：

    builtin-target := $(obj)/built-in.o

builtin-target 是一个 builtin-in.o 文件。在 297 行中看到：

    $(builtin-target): $(obj-y) FORCE
             $(call if_changed,link_o_target)

由此可见 builtin-in.o 文件依赖于各个 obj-y 。obj-y 定义在要编译的子目录的 Makefile 中，这些 Makefile 文件在 Makefile.build 的 43-44 行做了包含：

    kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
    include $(kbuild-file)

比如在 init 目录下可以看到 obj-y 的一行定义：

    obj-y                          := main.o version.o mounts.o

上面的这些 .o 文件又由 Makefile.build 中的 229-231 这几行的规则编译而成：

    $(obj)/%.o: $(src)/%.c FORCE
             $(call cmd,force_checksrc)
             $(call if_changed_rule,cc_o_c)

实际上就是将对应的 .c 文件编译成 .o 文件。如果都所有的 .c 文件都已经编译为相应的 .o 文件，那么就会由 Makefile.build 中的第 298 行命令将这些 .o 文件链接成 built-in.o 文件。
这里先分析 if_changed_rule 和 cc_o_c 的实现：
if_changed_rule 定义在 scripts/Kbuild.include 的 220-222 行中：

    if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
            @set -e;                                                             \
            $(rule_$(1)))

这里看到 arg-check 和 any-prereq 两个变量，它们分别定义在 scripts/Kbuild.include 的 188 和 200 行中：

    arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                        $(filter-out $(cmd_$@),   $(cmd_$(1))) )
    ... ...
    any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)

在 any-prereq 中，$? 表示所有比目标还要新的依赖文件；$^ 表示所有的依赖文件。
在 any-prereq 中，首先使用 $(filter-out $(PHONY),$?) 将 $? 中的所有伪目标去掉，不然可能会将 FORCE 这种目标也带进来，如果此时返回非空，那么说明有比目标还要新的依赖文件。$(wildcard $^) 匹配当前目录下的所有依赖文件(已经存在的)，然后再使用 $(filter-out $(PHONY) $(wildcard $^),$^) 将伪目标以及当前目录下匹配的文件列表从整个 $^ 列表中删除，如果返回不为空，那么说明某些依赖文件不存在，也就是说这些不存在的依赖文件还没生成 -- 这是因为某些依赖文件需要在编译时才会生成。
在 arg-check 中，$(1) 表示第 1 个参数，比如上面的 $(call if_changed_rule,cc_o_c) 中，$(1) 就是 cc_o_c ，所以 $(cmd_$(1) 就是表示 cmd_cc_o_c -- 这个变量可以在 Makefile.build 中的 179 或 194 行看到定义。它实际上表示的是这一次编译文件时所用到的命令行参数。
$@ 表示目标文件，从上面叙述可知，它就是 $(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_rule/cc_o_c/any-prereq/arg-check --] [-- top --]
Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip enabled