Makefile 文件对应内核版本:2.6.35.13
在编译内核时,可以将输出的各种 *.o 文件以及目标文件(如 vmlinux)输出到别的目录中,方法是通过在 make 时使用 O 选项指定输出的目标路径,比如:[beyes@beyes linux-2.6.35.13]$ make -j8 O=/home/beyes/kerstore/ vmlinux 这样,编译的输出都会放在 /home/beyes/kerstore/ 这个目录下。这里需要注意两点:
1. O 所指定的目录下面要先放置 .config 文件,否则会有如下类似的错误提示:***
*** You have not yet configured your kernel!
*** (missing kernel config file ".config")
***
*** Please run some configurator (e.g. "make oldconfig" or
*** "make menuconfig" or "make xconfig").
***
make[3]: *** [silentoldconfig] 错误 1
make[2]: *** [silentoldconfig] 错误 2
make[1]: *** 没有规则可以创建“include/config/kernel.release”需要的目标“include/config/auto.conf”。 停止。
make: *** [sub-make] 错误 2 2. 执行 make 命令必须在内核源代码的根目录下执行。这里在顶层 Makefile 中的注释有说明:# kbuild supports saving output files in a separate directory.
# To locate output files in a separate directory two syntaxes are supported.
# In both cases the working directory must be the root of the kernel src.
# 1) O=
# Use "make O=dir/to/store/output/files/"
# 2) Set KBUILD_OUTPUT
# Set the environment variable KBUILD_OUTPUT to point to the directory
# where the output files shall be placed.
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable. 由注释可以看到,在命令行中直接在 O 选项后指定路径和设置一个环境变量 KBUILD_OUTPUT 的效果是一样的。
下面分析执行带有 O 选项 make 命令时的前半部内容,所谓的前半部是指不涉及具体构建目标文件的过程:
来到第 97 行:
[Plain Text] 纯文本查看 复制代码 ifeq ($(KBUILD_SRC),)
由于这里 KBUILD_SRC 变量还未定义,所以必然为空,所以程序继续往下走。
来到 101-103 行:
[Plain Text] 纯文本查看 复制代码 ifeq ("$(origin O)", "command line")
KBUILD_OUTPUT := $(O)
endif
这里判断 O 选项是否来自命令行,是的话,就将目录信息 $(O) 赋值到变量 KBUILD_OUTPUT 中。
来到 106-107 行:
[Plain Text] 纯文本查看 复制代码 PHONY := _all
_all:
如果只是简单的执行 make 命令时,_all 就是默认的目标了。
来到 110 行:
[Plain Text] 纯文本查看 复制代码 $(CURDIR)/Makefile Makefile: ;
这只是为了避免顶层 Makefile 规则冲突。
来到 112-118 行:
[Plain Text] 纯文本查看 复制代码 ifneq ($(KBUILD_OUTPUT),)
# Invoke a second make in the output directory, passing relevant variables
# check that the output directory actually exists
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
$(error output directory "$(saved-output)" does not exist))
因为之前已经用 O 选项所带的目录信息赋值到 KBUILD_OUTPUT 变量中,所以第 1 条判断语句不为空,接着又将这个路径信息保存到 saved-output 变量中。然后通过 shell 函数执行 shell 命令,主要是测试所给的目录是否存在,不存在的话通过 error 函数报出错误信息,然后停止 make 的继续执行。如果指定的目录是存在的,那么程序继续往下走。
来到 12 行:
[Plain Text] 纯文本查看 复制代码 PHONY += $(MAKECMDGOALS) sub-make
MAKECMDGOALS 变量是 make 的一个内置变量,它表示的是所要构建目标的一个终极列表。这里是表示,将 MAKECMDGOALS 所表示的所有目标以及 sub-make 都定义为伪目标。
来到 122-123 行:
[Plain Text] 纯文本查看 复制代码 $(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
$(Q)@:
这里使用 filter-out 函数将 $(MAKECMDGOALS) 表示的所有目标中去掉 _all sub-make $(CURDIR)/Makefile 这 3 个目标,此后剩下的目标和 _all 这两个目标都将依赖于 sub-make ,而 $(Q)@: 表示什么都不做,它的作用仅仅是提示要先去实现 sub-make 这个依赖,而实现了 sub-make 这个依赖后也就相当于实现了 $(MAKECMDGOALS) 和 _all 这两个目标了。
来到 125-129 行:
[Plain Text] 纯文本查看 复制代码 sub-make: FORCE
$(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
KBUILD_SRC=$(CURDIR) \
KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile \
$(filter-out _all sub-make,$(MAKECMDGOALS))
在这里,实际上是对 sub-make 目标的实现。
关于 $(KBUILD_VERBOSE:1=) 这段的语法分析见 :http://www.groad.net/bbs/read.php?tid-3842.html
这里我们并不指定 $(KBUILD_EXTMOD) ,也就是我们不是在编译外部模块,而假定是在编译 vmlinx ,所以 KBUILD_EXTMOD 变量为空。
底下 $(filter-out _all sub-make,$(MAKECMDGOALS)) 这一行再次用 filter-out 函数将 _all 和 sub-make 这两个目标去掉,剩下的只有 $(MAKECMDGOALS) 这个目标列表里的目标了。如果我们只是 make vmlinux 那么 $(MAKECMDGOALS) 就表示 vmlinux 。$(CURDIR) 是内置变量,表示当前目录。
所以,上面的几条指令可以写成:make -C [输出的外部目录] KBUILD_SRC=`pwd` KBUILD_EXTMOD=“” -f `pwd`/Makefile [要生成的目标]
从上面看到,在此我们重新调用了顶层 Makefile ,这是递归调用。当我们再次调用顶层 Makefile 时,由于我们在上面的命令中的 KBUILD_SRC 变量已经被赋值,所以当再次来到第 97 行中的 ifeq ($(KBUILD_SRC),) 判断时,是不会再进去到它的代码块中(从 97-134 行) 。这样,程序就会直接跳到 137 行的 ifeq ($(skip-makefile),) ,因为此时 skip-makefile 还未定义,故为空,所以程序得以继续往下执行。后面的执行就是上面所说的 “下半部”,这部分涉及到了具体目标文件的构建过程。当 “下半部” 执行完毕后会返回到 131-134 行,即:
[Plain Text] 纯文本查看 复制代码
# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)
这时,skip-makefile 变量被赋值为 1 。此时,程序会再次来到 137 行:
[Plain Text] 纯文本查看 复制代码 # We process the rest of the Makefile if this is the final invocation of make
ifeq ($(skip-makefile),)
上面的注释意思是:如果这时最终的一次调用 make,那么我们处理 Makefile 余下的部分。所谓的 “最终一次调用” 就是说 “递归到最底层” 的那一次。如上面用 O 指定输出路径,会进行一次递归,也就是在进入第 2 次调用 Makefile 时,我们会往下执行;当不指定 O 时,如只是 make vmlinux 时,make 会直接往下走。所以,当上面的递归返回到第 1 层 Makefile 时,这里由于 skip-makefile 值为 1,程序直接跳到 Makefile 最底部,从而结束了 Makefile 这个过程。
从上面的分析可以看到,O 选项所对应的代码块从 97-134 这里,如果带 O 选项就分析这一块代码,如果不带 O,则略过此段的分析。 |