编译内核最后一行的信息:
arm-none-linux-gnueabi-ld -EL -r -o vmlinux.o
arch/arm/kernel/head.o
arch/arm/kernel/init_task.o
init/built-in.o
--start-group
usr/built-in.o
arch/arm/kernel/built-in.o
arch/arm/mm/built-in.o
arch/arm/common/built-in.o
arch/arm/mach-s5p6450/built-in.o
arch/arm/plat-s5p/built-in.o
arch/arm/plat-samsung/built-in.o
arch/arm/nwfpe/built-in.o
arch/arm/vfp/built-in.o
kernel/built-in.o
mm/built-in.o
fs/built-in.o
ipc/built-in.o
security/built-in.o
crypto/built-in.o
block/built-in.o
arch/arm/lib/lib.a
lib/lib.a
arch/arm/lib/built-in.o
lib/built-in.o
drivers/built-in.o
sound/built-in.o
firmware/built-in.o
net/built-in.o
--end-group
编译内核最后一行结束 ,上面好多行本来是一行,用回车隔开了
顶层Maiefile里面关建行
include $(srctree)/scripts/Kbuild.include //定义变量 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
include $(srctree)/arch/$(SRCARCH)/Makefile //扩展变量core-y 定义变量head-y
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o //定义在arch/arm/makefile中 MMUEXT为空
init-y := init/
drivers-y := drivers/ sound/ firmware/
net-y := net/
libs-y := lib/
core-y := usr/
//定义在arch/arm/makefile中 CONFIG_*=y
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
platdirs := $(patsubst %,arch/arm/plat-%/,$(plat-y))
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += $(machdirs) $(platdirs)
core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
core-$(CONFIG_VFP) += arch/arm/vfp/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m)))
vmlinux-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \
$(init-n) $(init-) \
$(core-n) $(core-) $(drivers-n) $(drivers-) \
$(net-n) $(net-) $(libs-n) $(libs-))))
init-y := $(patsubst %/, %/built-in.o, $(init-y)) //通过patsubst init-y=init/built-in.o
core-y := $(patsubst %/, %/built-in.o, $(core-y))
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
net-y := $(patsubst %/, %/built-in.o, $(net-y))
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)
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
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))
vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
$(call if_changed_rule,vmlinux-modpost) //也就是编译的最后一行信息,这一行没看懂
$(vmlinux-dirs): prepare scripts //通过这一行递归各各子目录,生成子目录的built-in.o
$(Q)$(MAKE) $(build)=$@
zImage Image xipImage bootpImage uImage: vmlinux //arch/arm/makefile boot=arch/arm/boot
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE //arch/arm/boot/makefile
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
分析编译信息:
make -n | grep “make -f”
make -f scripts/Makefile.build obj=arch/arm/tools include/asm-arm/mach-types.h
make -f scripts/Makefile.build obj=scripts/basic
make -f scripts/Makefile.build obj=.
make -f scripts/Makefile.build obj=. missing-syscalls
make -f scripts/Makefile.build obj=scripts
make -f scripts/Makefile.build obj=scripts/mod
make -f scripts/Makefile.build obj=init
make -f scripts/Makefile.build obj=usr
make -f scripts/Makefile.build obj=arch/arm/kernel
make -f scripts/Makefile.build obj=arch/arm/mm
make -f scripts/Makefile.build obj=arch/arm/common
make -f scripts/Makefile.build obj=arch/arm/mach-s5p6450
.........................................
然后依次递归地调用源代码中的Makefile
由于scripts/Makefile.build后面没跟目标,所以默认为第一个目标:
.PHONY: __build
__build:
010 # Read .config if it exist, otherwise ignore
011 -include .config
013 include $(if $(wildcard $(obj)/Kbuild), $(obj)/Kbuild, $(obj)/Makefile)
015 include scripts/Makefile.lib
这里可以看到,scripts/Makefile.build执行时会include .config文件。.config是make menuconfig后生成的内核配置文件。
里面有如下语句:
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_ASUS=m
CONFIG_ACPI_IBM=m
.........
以前我一直对它的格式表示奇怪,现在很清楚了,它们是作为makefile的一部分,通过读取CONFIG_XXX的值就可以知道他们是作为模块还是作为内核
的一部分而编译的。此外,还包含了$(obj)/Makefile。这就是通过在make时传递目录名$(obj)间接调用Makefile的手法。对于内核普通代码所对应的
Makefile而言,里面只是对obj-m obj-y,-objs等变量进行赋值操作。接下去是include scripts/Makefile.lib。正如它的文件名所示,这类似于一个
库文件。它负责对obj-m obj-y,-objs等变量进行加工处理。从中提取出subdir-ym等变量,这是个很重要的变量,记录了需要递归调用的子目录。以
后递归调用Makefile全靠它了。这里也充分体现了GNU make对字符串进行操作的强大功能。回到Makefile.build。这时,重要变量$(builtin-target),
$(subdir-ym)等都已经计算完毕。开始列依赖关系和具体操作了。
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m)) \
$(subdir-ym) $(always)
@:
$(builtin-target)是指当前目录下的目标文件,即$(obj)/built-in.o
如前文所说,$(subdir-ym)用来递归调用子目录的Makefile
# Descending
# ---------------------------------------------------------------------------
.PHONY: $(subdir-ym)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
通过这种方式,实现了对某个目录及其子目录的编译。