Kernel的Makefile其实常常见到,不过也就是用用,没有机会仔细分析。这里简单分析下顶层Makefile,也算是对我们经常执行的make命令的执行过程有所了解。
Makefile以2.6.29为例,版本之间差异应该不会太大。
Line 1 ~ Line 6
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 29
kernel的版本号及名称
Line 7 ~ Line 136
L7: # *DOCUMENTATION*
......
......
L136: endif # ifeq ($(KBUILD_SRC),)
这一段对make命令的几个参数进行了处理:
V=: verbose,打印更详细的log
C=: check source
M=: build modules
SUBDIRS=: build modules
O=: output directory 指定另外的编译输出目录
KBUILD_SRC=: 未知 # KBUILD_SRC is not intended to be used by the regular user (for now)
Line 138 ~ Line 159
L138: ifeq ($(skip-makefile),)
......
......
L159: export srctree objtree VPATH TOPDIR
这一段给srctree objtree VPATH TOPDIR几个变量赋值,具体的值也和之前的几个参数相关。
Line 169 ~ Line 221
L169: SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
......
......
L221: ifeq ($(ARCH),m68knommu)
hdr-arch := m68k
endif
这一段设定了交叉编译的几个变量,ARCH指定了目标编译平台,可以在command line中赋值,也可以直接在Makefile中直接修改。CROSS_COMPILE指定交叉编译器的路径,可以在command line中赋值,也可以直接修改Makefile,或者写入根目录的某个文件中,在Makefile中读取,如:
CROSS_COMPILE := $(shell if [ -f .cross_compile ]; then \
cat .cross_compile; \
fi)
Line 223
KCONFIG_CONFIG ?= .config
指定config文件,默认为当前目录的.config,这里用的是?=,这也就意味着可以在command line中指定其他的config文件。
Line 225 ~ Line 233
指定本地编译器即编译参数
Line 235 ~ Line 263
export KBUILD_MODULES KBUILD_BUILTIN
export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD
这一段判定是否需要编译modules。判定原则是make/make all/make modules*/需要编译模块,其他则不用。
Line 265 ~ Line 303
export quiet Q KBUILD_VERBOSE
根据参数判定是否输出详细build信息,V=1要求打印详细信息,make -s进入silent mode
Line 306
# Look for make include files relative to root of kernel src
MAKEFLAGS += --include-dir=$(srctree)
# We need some generic definitions (do not try to remake the file).
$(srctree)/scripts/Kbuild.include: ;
include $(srctree)/scripts/Kbuild.include
Line 315 ~ Line 366
L315: AS = $(CROSS_COMPILE)as
L366: export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
这一段根据CROSS_COMPILE指定编译用的CC, AS, LD.., 以及编译参数。
Line 371
export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
为module编译指定路径。由M=指定。
Line 408 ~ Line 460
这一段通过分析command line,判断make的目标是config还是build,或者是mixed-target,即先config再build。
在这一段中,有以下几个中间变量:config-targets, mixed-targets, dot-config。config-targets表示编译目标中包括config,mixed-targets表示有多个编译目标,dot-config表示是否需要包含config文件,凡config及build行为都需要包含config文件,其他则不用。
对于config,makefile相关执行语句为:
config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
具体的原因还要分析。。
Line 465
ifeq ($(KBUILD_EXTMOD),)
# Additional helpers built in scripts/
# Carefully list dependencies so we do not try to build scripts twice
# in parallel
PHONY += scripts
scripts: scripts_basic include/config/auto.conf
$(Q)$(MAKE) $(build)=$(@)
# Objects we will link into vmlinux / subdirs we need to visit
init-y := init/
drivers-y := drivers/ sound/ firmware/
net-y := net/
libs-y := lib/
core-y := usr/
endif # KBUILD_EXTMOD
init, drivers, sound, firmware, net, lib, usr等必须的子目录。
Line 481 ~ Line 600
这一段对各种FLAG进行配置。
接下来进入实际的build部分,默认最终生成的image是vmlinux。
对于vmlinux的生成,makefile有注释说明:
# Build vmlinux
# ---------------------------------------------------------------------------
# vmlinux is built from the objects selected by $(vmlinux-init) and
# $(vmlinux-main). Most are built-in.o files from top-level directories
# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
# Ordering when linking is important, and $(vmlinux-init) must be first.
#
# vmlinux
# ^
# |
# +-< $(vmlinux-init)
# | +--< init/version.o + more
# |
# +--< $(vmlinux-main)
# | +--< driver/built-in.o mm/built-in.o + more
# |
# +-< kallsyms.o (see description in CONFIG_KALLSYMS section)
注释说明vmlinuz主要由vmlinux-init和vmlinux-main组成。
vmlinux依赖关系如下:
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
部分变量展开为:
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(SRCARCH)/kernel/vmlinux.lds
export KBUILD_VMLINUX_OBJS := $(vmlinux-all)
而后可依次展开,直到所有的build-in的obj都编译完成,然后根据lds进行link,但是link的过程再哪里?
vmlinux之后是modules,firmware,kernel headers等其他的target。不再细述。
未解决的问题:
1,mix target的问题 ,当有两个target的时候,下面的语句是如何实现 handle them one by one的?
ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.
%:: FORCE
$(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@
else
2, config target是如何进行编译的,如上面所提到的针对config的代码:
config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
3, .tmp_vmlinux1, .tmp_vmlinux2, .tmp_vmlinux3在makefile中没有被明显的使用,他们是如何被依赖的?