|
在内核源码路径下,scripts/ 下有一个 Makefile.build 文件,这个文件的作用是对一个指定的目录进行编译。那么它是怎么做到的呢?答案正是通过 include 关键字。
对于 include 关键字,可以参考:http://www.groad.net/bbs/read.php?tid-3082.html 。这篇帖子里对 include 做了基本的介绍和演示,但其中有一句话比较重要:make 命令执行时,它会找到所有 include 所指定的文件,并将它们的内容放置在当前的位置。
这里通过修改内核源码根目录下的 Makefile 以及 Makefile.build 来观察整个作用过程。
首先了解,scripts 目录下有一个文件为 Kbuild.include 。这个文件里面对一些通用变量做了定义,其中它包含了对主 Makefile 文件中 $(build) 变量的定义:
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build :=-f $(if$(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
而主 Makefile 文件又是通过以下语句将 Kbuild.include 包含进来:include $(srctree)/scripts/Kbuild.include 这里需要提醒一下,Kbuild.include 里面没有定义任何的目标,所以这里用 include 包含一点问题都没有,如果是定义了目标,那可能会出现问题,而出现的问题就是下面要说的 Makefile.build 的情况。
接下来,在主 Makefile 的下面两行:
# We need some generic definitions (do not try to remake the file).
$(srctree)/scripts/Kbuild.include: ;
include $(srctree)/scripts/Kbuild.include
的底下添加:
stub:
@echo "=================================="
@make $(build)=helloworld
这里,我们自定义了自己一个 stub 目标,为的是跟踪 Makefile.build 的流程。
通过 make 的 -f 参数以及在 Makefile 文件间传递参数 这篇帖子我们知道 Makefile 文件之间是如何传递参数的。如上面,我们将 helloworld 这个参数传递给 $(build) 变量中。
接着手动在内核源码顶层目录下创建一个 helloworld 的目录。然后在这个目录中创建一个很简单的 Makefile 文件,其内容为:
接着,转到 scripts 目录下,修改一下 Makefile.build 文件:
1. 屏蔽掉文件顶上的 __build: 这个目标:
2. 来到:
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if$(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
这里,我们先屏蔽掉 include $(kbuild-file) 这一句,并在底下添加一个自定义的目标:
temp:
@echo "---------- $(kbuild-dir) -----------"
@echo "---------- $(kbuild-file) ------------"
现在可以测试一下 make stub 这个目标了:[beyes@SLinux linux-2.6.34.9]$ make stub
==================================
---------- /home/beyes/kernel/linux-2.6.34.9/helloworld -----------
---------- /home/beyes/kernel/linux-2.6.34.9/helloworld/Makefile ------------ 从输出可以看到:
$(kbuild-dir) 表示的是我们要编译的子目录 helloworld 。
$(kbuild-file) 表示的是要编译的子目录下的 Makefile 文件。而就是在这个文件中,它含有要编译的目标!
关于上面涉及的 filter 函数说明可参考:http://www.groad.net/bbs/read.php?tid-2940-fpage-2.html
关于 wildcard 说明可参考:http://www.groad.net/bbs/read.php?tid-2947.html
现在我们可以打开上面被屏蔽的 include $(kbuild-file) 这句话了,解除屏蔽后,我们再 make stub 一下看会有什么结果:[beyes@SLinux linux-2.6.34.9]$ make stub
==================================
i am here 从输出可以看到,由于 include 的 $(kbuild-file) 中另有要生成的目标,从而转去生成那里的目标,而之前的 temp 目标就不再执行编译生成,也就是说 temp 目标被新 include 进来的 all: 目标给覆盖了 (override ) 。
最后,上面之所以要先屏蔽 __build 的目的是为了更好的演示如何将另外目录下的 Makefile 文件包含进来。如果没有屏蔽,那么将执行的是底下的 __build 目标,而不是我们自定义的 temp,因为 __build 已经先得到声明。 |
|