【IMX6ULL学习笔记】七、Linux 顶层Makefile
一、Linux 工程目录分析

二、顶层 Makefile 详解
1、配置工程,生成.config配置文件:
make xxx_defconfig
会调用顶层的Makefile的 %config 规则。
第 534 行:引用 arch/arm/Makefile 这个文件,这个文件很重要, zImage、uImage 等这些文件就是由 arch/arm/Makefile 来生成的。
第 540 行:%config 规则: %通配符,当输入“make xxx_defconfig”的时候就会匹配到%config 目标
%config: scripts_basic outputmakefile FORCE
    $(Q)$(MAKE) $(build)=scripts/kconfig $@
第一步:依赖部分
目标 %config 依赖于 scripts_basic、outputmakefile、FORCE
①FORCE目标:
FORCE 在顶层 Makefile的 1610 行有如下定义:
PHONY += FORCE
FORCE:
FORCE 是没有规则和依赖的,所以每次都会重新生成 FORCE。当 FORCE 作为其他目标的依赖时,由于 FORCE 总是被更新过的,因此依赖所在的规则总是会执行的。即将FORCE当做依赖时,对应的目标规则总是会被执行。
②scripts_basic目标:

该目标会执行以下命令:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
其中:
Q是显示方式:静默make -s;详细make V=1;不显示make V=0
MAKE=make
build定义在scripts\kbuild.include
    build := -f $(srctree)/scripts/Makefile.build obj
    展开后:
    build := -f ./scripts/Makefile.build obj

展开后:
@make -f ./scripts/Makefile.build obj=scripts/basic
@rm -f .tmp_quiet_recordmcount
最终会调用文件./scripts/Makefile.build
③outputmakefile目标:

可以通过 echo 查看 KBUILD_SRC 为空:
mytest:
    @echo KBUILD_SRC = $(KBUILD_SRC)
所以该目标规则没有执行如何命令。
第二步:命令部分
目标 %config 依赖于 scripts_basic、outputmakefile、FORCE ,执行以下命令:
 $(Q)$(MAKE) $(build)=scripts/kconfig $@
展开:
make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
也跟文件./scripts/Makefile.build 有关
第三步:Makefile.build
上面的分析最后指向以下两条命令:
make -f ./scripts/Makefile.build obj=scripts/basic
make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
1、 scripts_basic 目标对应的命令:
make -f ./scripts/Makefile.build obj=scripts/basic
打开文件 scripts/Makefile.build,有如下代码:
# Modified for U-Boot
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif
# 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)
使用@echo打印各个变量值,结果如下:
src= scripts/basic
kbuild-dir = ./scripts/basic
kbuild-file = ./scripts/basic/Makefile
include ./scripts/basic/Makefile
其中src的值即为obj=scripts/basic的值,并且包含了scripts/basic/目录下的Makefile。
make执行时未指定目标,会执行Makefile.build中的默认目标,如下:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
	 $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
	 $(subdir-ym) $(always)
	@:
其中KBUILD_BUILTIN = 1、KBUILD_MODULES = 0,展开后即为:
__build:$(builtin-target) $(lib-target) $(extra-y)) $(subdir-ym) $(always)
@:
在 scripts/Makefile.build 的默认执行目标末尾使用@echo 打印各变量值,得:
builtin-target =
lib-target =
extra-y =
subdir-ym =
always = scripts/basic/fixdep scripts/basic/bin2c
展开后只剩 always ,即 $(always) = scripts/basic/fixdep scripts/basic/bin2c,因此需要先编译scripts/basic/fixdep.c 和 scripts/basic/bin2c.c 生成fixdep、bin2c这个两个软件。
2、 %config 目标对应的命令:
make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
src的值即为obj=scripts/basic的值,所以Makefile.build中各个变量值如下:
src= scripts/kconfig
kbuild-dir = ./scripts/kconfig
kbuild-file = ./scripts/kconfig/Makefile
include ./scripts/kconfig/Makefile
include包含了./scripts/kconfig目录下的Makefile,执行make时会调用scripts/kconfig/ Makefile中的内容,此文件有如下所示内容:
%_defconfig: $(obj)/conf
    $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
# Added for U-Boot (backward compatibility)
%_config: %_defconfig
    @:
目标%_defconfig 刚好和我们输入的 xxx_defconfig 匹配,依赖为$(obj)/conf,展开后就是 scripts/kconfig/conf,该依赖会编译 scripts/kconfig/conf.c 生成 conf 这个软件。
得到 scripts/kconfig/conf 以后就要执行目标%_defconfig 的命令:
 $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
将其展开就是:
@ scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig
结果是将配置输出到.config 文件中,最终生成 Linux 根目录下的.config 文件。
2、make 生成 vmlinux、zImag、uImag 等文件
make 或 make all  //编译linux,未指定目标将执行Makefile中默认目标

_all 的依赖如下图所示:

如果 KBUILD_EXTMOD(编译模块) 为空的话 _all 依赖于all,all 定义如下:
all: vmlinux

(1)、vmlinux依赖分析:
vmlinux 依赖 scripts/link-vmlinux.sh 和 $(vmlinux-deps) ,如下:

上图第912 行定义了 vmlinux-deps,值为:
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

上图第907行:
KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
其中 SRCARCH=arm,展开即:
KBUILD_LDS= arch/arm/kernel/vmlinux.lds
综上所述,vmlinux 的依赖为:
scripts/link-vmlinux.sh、$(head-y) 、$(init-y)、$(core-y) 、$(libs-y) 、$(drivers-y) 、$(net-y)、arch/arm/kernel/vmlinux.lds 和 FORCE
重点来看一下\((head-y) 、\)(init-y)、\((core-y) 、\)(libs-y) 、\((drivers-y) 和\)(net-y)这六个变量的值:
①head-y依赖:
head-y 定义在文件 arch/arm/Makefile 中,内容如下:
head-y := arch/arm/kernel/head$(MMUEXT).o
不使能 MMU 时 MMUEXT=-nommu,使能 MMU 时为空,因此 head-y 最终的值为:
head-y = arch/arm/kernel/head.o
②init-y、drivers-y、net-y依赖:
在顶层 Makefile 中有如下代码:
init-y	:= init/
drivers-y := drivers/ sound/ firmware/
net-y	:= net/
......
init-y	:= $(patsubst %/, %/built-in.o, $(init-y))
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
net-y	:= $(patsubst %/, %/built-in.o, $(net-y))
init-y、libs-y、drivers-y 和 net-y 最终的值为:
init-y = init/built-in.o
drivers-y = drivers/built-in.o sound/built-in.o firmware/built-in.o
net-y = net/built-in.o
③lib-y依赖
libs-y 基本和 init-y 一样,在顶层 Makefile 中存在如下代码:
libs-y := lib/
......
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)
libs-y 应该等于“lib.a built-in.o”,这个只正确了一部分!因为在 arch/arm/Makefile 中会向 libs-y 中追加一些值,代码如下:
libs-y := arch/arm/lib/ $(libs-y)
arch/arm/Makefile 将 libs-y 的值改为了:arch/arm/lib $(libs-y),展开以后为:
libs-y = arch/arm/lib lib/
libs-y 最终应该为:
libs-y = arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o
④core-y依赖
core-y 和 init-y 也一样,在顶层 Makefile 中有如下代码:
core-y := usr/
......
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
但是在 arch/arm/Makefile 中会对 core-y 进行追加,代码如下:
core-$(CONFIG_FPE_NWFPE)  += arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE)  += $(FASTFPE_OBJ)
core-$(CONFIG_VFP)    += arch/arm/vfp/
core-$(CONFIG_XEN)    += arch/arm/xen/
core-$(CONFIG_KVM_ARM_HOST)   += arch/arm/kvm/
core-$(CONFIG_VDSO)   += arch/arm/vdso/
# If we have a machine-specific directory, then include it in the build.
core-y        += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y        += arch/arm/probes/
core-y        += arch/arm/net/
core-y        += arch/arm/crypto/
core-y        += arch/arm/firmware/
core-y        += $(machdirs) $(platdirs)
第 1~6 行:根据不同的配置向 core-y 追加不同的值,比如使能 VFP 的话就会在 .config 中有 CONFIG_VFP=y 这一行,那么 core-y 就会追加“arch/arm/vfp/”。
第 9~14 行:就是对 core-y 直接追加的值。
在顶层 Makefile 中有如下一行:
core-y := $(patsubst %/, %/built-in.o, $(core-y))
经过上述代码的转换,最终 core-y 的值为:
core-y = usr/built-in.o
        arch/arm/vfp/built-in.o \
        arch/arm/vdso/built-in.o
        arch/arm/kernel/built-in.o \
        arch/arm/mm/built-in.o
        arch/arm/common/built-in.o \
        arch/arm/probes/built-in.o
        arch/arm/net/built-in.o \
        arch/arm/crypto/built-in.o
        arch/arm/firmware/built-in.o \
        arch/arm/mach-imx/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
(2)、vmlinux命令分析:
vmlinux 的依赖分析完成,接下来分析 vmlinux 执行的命令:
+$(call if_changed,link-vmlinux)
该命令最终会调用 scripts/link-vmlinux.sh 这个脚本,根据 arch/arm/kernel/vmlinux.lds 链接文件,将各个子目录下的所有 built-in.o、*.a 链接生成 vmlinux。
(3)、vmlinux生成zImag、uImag等:
顶层Makefile中有如下定义:
include arch/$(SRCARCH)/Makefile
export KBUILD_DEFCONFIG KBUILD_KCONFIG

展开即:
include arch/arm/Makefile
在 arch/arm/Makefile 中的默认执行目标如下:

展开即:
all : zImag dtbs
arch/arm/Makefile 中还有如下定义:
BOOT_TARGETS  = zImage Image xipImage bootpImage uImage
INSTALL_TARGETS = zinstall uinstall install
PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS)
$(BOOT_TARGETS): vmlinux
  $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

展开即:
zImage Image xipImage bootpImage uImage: vmlinux
    $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
Makefile 默认执行的目标依赖于 zImag ,要编译 zImage,那么命令展开以后如下所示:
@ make -f ./scripts/Makefile.build obj=arch/arm/boot MACHINE=arch/arm/boot/zImage
是使用 scripts/Makefile.build 文件来完成 vmlinux 到 zImage 的转换。

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号