linux kernel Makefile编译流程分析

版权声明:国内网络上重复文章太多了,本文为博主原创的文章,未经博主允许就不要转载了。 https://blog.csdn.net/dwdwdw2/article/details/78587782

1. 文章说明


内核版本号为:4.11.4,针对x86平台,前提是存在.config文件
需要读者有基础Makefile知识
分析只输入make命令时的情形,只分析主要流程,其它的像变量赋值等部分只分析会影响流程执行的内容。
不会讲解Makefile文件中出现的函数,如果不懂,可以bing。
分析顺序为:先分析框架,再慢慢细化。分析每个模块时,也是先框架再细化的顺序。

2. 先看看哪些主语句块是有效的


Makefile中存在很长的if语句块,需要确定哪些行的语句是有效的。


 (1) line 1 ~ line 117 有效


主要是变量的赋值,环境变量的设置


(2) line 118 ~ line 158,其中line 137 ~ line 157的语句无效


       由于只输入了make,因此KBUILD_SRC为空,会解析line 118 ~ line 158的语句。这部分中,line 137 ~ line 157的语句无效。原因是编译时只输入了make,导致line 122行条件为假,因此KBUILD_OUTPUT为空值,line 137行的语句为假,所以line 137 ~ line 157的语句无效。
        

(3) line 161 ~ line 1698,其中line 516 ~ line 549、line 1184 ~ line 1245、line 1457 ~ line 1533语句无效


       在上述(2)中的line 118 ~ line 158部分中,line 137 ~ line 157的语句无效,而skip-makefile在line 156行赋值,所以skip-makefile为空值,因此line 161行的条件为真,所以line 161 ~ line 1698的语句有效。


       在这部分中,line 516 ~ line 549语句无效。原因是编译时只输入了make,因此line 495,line 502,line 510为假,所以config-targets,mixed-targets,dot-config的值不会改变,还是line 491 ~ line 493的初始值,即config-targets = 0,mixed-targets =0,dot-config = 1,因此line 516 ~ line 549无效


CONFIG_MODULES未定义,line 1184行条件为假,line 1184 ~ line 1245的语句不会被处理,line 1247 ~ line 1259的会被处理


        在line 188行之前,SUBDIRS没有被定义,并且执行Makefile时只输入了make,所以SUBDIRS为空值,后续的line 189,line 193都不会执行,因此KBUILD_EXTMOD为空值,line 926条件为真,而line 1456对应于line 926的ifeq语句,因此从line 1457 ~ line 1533的语句不会被处理




3. 主目标介绍


寻找主目标时只需要关注上述2.中介绍的有效的语句块。


(1) 源码根目录下Makefile line 128 _all:


这是第一目标


(2) 源码根目录下Makefile line 200 _all: all 


        重载了第一目标。line 200行在ifeq语句中,下面分析为什么line200行会生效。

         在line 188行之前,SUBDIRS没有被定义,执行Makefile时只输入了make,所以SUBDIRS为空值,后续的line 189,line 193都不会执行,因此KBUILD_EXTMOD 为空值。KBUILD_EXTMOD为空值,line 200行语句有效会重载目标all 
        
(3) 源码根目录下Makefile line 623 all: vmlinux


定义目标all的依赖


(4) arch/x86/Makefile line 271 all: bzImage


       line 230设置SUBARCH值。SUBARCH值会赋给line 257行的ARCH(若编译时输入了make ARCH=...,则line 257行不会赋值),ARCH值会决定SRCARCH的值,而后续的line 630会根据SRCARCH的值决定引入哪一个架构的Makefile文件。在x86架构下编译内核时,前述的line 230 SUBARCH=x86,line 630行会引入arch/x86/Makefile。


       arch/x86/Makefile文件line 271行会重载目标all:bzImage


(5) arch/x86/Makefile line 276 bzImage: vmlinux


目标bzImage依赖目标vmlinux


(6) 源代码根目录下的Makefile line 982 vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE


目标vmlinux在源代码根目录下Makefile的line 982行声明


综上所述,Makefile中第一目标是源代码根目录下Makefile line 200行的 _all:all,
而目标all定义在arch/x86/Makefile line 271 行all: bzImage,
bzImage定义在arch/x86/Makefile line 276 行bzImage: vmlinux,
目标vmlinux定义在源代码根目录下的Makefile line 982行 vmlinux: 

4. 生成主目标过程分析


在前述分析中,目标依赖是

_all:all
all:bzImage

bzImage:vmlinux

vmlinux:scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE


从vmlinux目标所需的依赖可知,依赖生效的顺序是

[1] scripts/link-vmlinux.sh => 
[2] vmlinux_prereq => 
[3] $(vmlinux-deps) => 
[4] FORCE

4.1 vmlinux的依赖scripts/link-vmlinux.sh存在于源代码中,不需要分析这一依赖。

4.2 处理vmlinux的依赖vmlinux_prereq

vmlinux的依赖vmlinux_prereq是一个目标,定义于源码根目录Makefile的

line 959 vmlinux_prereq: $(vmlinux-deps) FORCE

4.2.1 vmlinux_prereq


vmlinux_prereq的依赖$(vmlinux-deps)的值定义于源码根目录Makefile的


line 953 vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

而$(vmlinux-deps)目标定义于源码根目录Makefile的

line 992 $(sort $(vmlinux-deps)): $(vmlinux-dirs)

这行语句后面没有对应的命令,$(vmlinux-dirs)在后续内容中分析,而目标vmlinux_prereq对应的命令比较简单,不进行分析。对vmlinux_prereq生成过程的分析结束。

下面分析一下vmlinux-dirs。
                
4.2.1.1 vmlinux-dirs的值

vmlinux-deps的依赖是$(vmlinux-dirs),$(vmlinux-dirs)是文件夹,它的值定义于源码根目录Makefile的

line 929 vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
line 930              $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
line 931              $(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))

从中可以看出vmlinux-dirs的值依赖于init-y,init-m,core-y,core-m,drivers-y,drivers-m,net-y,net-m,libs-y,libs-m,virt-y的值,这些变量在以下位置处赋值(忽略内核配置项的值y,n,m的影响)

源码根目录Makefile:

line 565 init-y := init/

line 566 drivers-y := drivers/ sound/ firmware/

line 567 net-y := net/

line 568 libs-y := lib/
line 569 core-y := usr/
line 570 virt-y := virt/
line 927 core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/

arch/x86/Makefile:
line 248 drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/

line 249 drivers-$(CONFIG_PCI)            += arch/x86/pci/

line 250

line 251 # must be linked after kernel/

line 252 drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/

line 253 
line 254 # suspend and hibernation support
line 255 drivers-$(CONFIG_PM) += arch/x86/power/
line 256 
line 257 drivers-$(CONFIG_FB) += arch/x86/video/
line 258 
line 259 drivers-$(CONFIG_RAS) += arch/x86/ras/

arch/x86/Makefile:

line 242 libs-y  += arch/x86/lib/


arch/x86/Makefile:

line 245 core-y += arch/x86/


不会包括下述内容
arch/x86/Makefile.um:

line 1 core-y += arch/x86/crypto/

原因:

arch/x86/Makefile.um会在文件arch/um/Makefile中引入,位置在line 47 include $(HOST_DIR)/Makefile.um。在arch/um/Makefile中有如下语句:


line 34 HEADER_ARCH     := $(SUBARCH)

line 44 HOST_DIR := arch/$(HEADER_ARCH)


SUBARCH的值在源码根目录Makefile line 230赋值

        而引入arch/um/Makefile的情形是在编译时输入make ARCH=um,此时源码根目录Makefile的line 257 ARCH ?= $(SUBARCH)不会生效,导致后续的源码根目录Makefile的line 262 SRCARCH := $(ARCH)的值为um,进而源码根目录Makefile的line 630 include arch/$(SRCARCH)/Makefile引入了arch/um/Makefile。而在编译时只输入了make的情形下,ARCH!=um,因此不会引入arch/um/Makefile,进而不会引入arch/x86/Makefile.um。


注:um指的是User-mode Linux,是一种虚拟化机制。


4.2.1.2 $(vmlinux-dirs)处理过程分析


$(vmlinux-dirs)目标定义于源码根目录Makefile的


line 1001 $(vmlinux-dirs): prepare scripts

line 1002     $(Q)$(MAKE) $(build)=$@


在依赖prepare scripts生成后,会执行line 1002行的$(Q)$(MAKE) $(build)=$@
其中
(1) $(Q)的值决定了是否简化make过程中的输出,不需要过多分析。

(2) $(MAKE) MAKE不是Makefile里面的变量,是make命令内置的环境变量,它的值是"make"

(3) $(build) build 定义于scripts/Kbuild.include的


line 184 build := -f $(srctree)/scripts/Makefile.build obj


注:scripts/Kbuild.include在源代码根目录Makefile中line 346

       行通过include引入 

srctree的值定义于源码根目录Makefile的line 205 ~ line 215,因为KBUILD_SRC的值为空,因此srctree的值为“.”,所以build的值为

line 184 build := -f ./scripts/Makefile.build obj

(4) $@代表的是目标,详细含义及用法可以网上搜索。

关于prepare,scripts,$(vmlinux-dirs)的生成过程,后续会以示例的形式分析部分内容,未提及的部分可以参考示例,举一反三来理解。


 4.2.1.2.1 prepare

                            

prepare目标定义于源码根目录Makefile的下述行


line 1050 prepare: prepare0 prepare-objtool


这里以目标prepares0的命令执行过程为例来分析,其它依赖的生成过程可以以此类推来理解。


4.2.1.2.1.1 prepare0


        这里分析目标prepare0的生成命令,对于prepare0的依赖的生成过程,比较简单的部分不进行分析,其它的可以参考生成目标prepare0的命令的解析来理解。

prepare0目标定义于源码根目录Makefile的下述行


line 1046 prepare0: archprepare gcc-plugins
line 1047     $(Q)$(MAKE) $(build)=.

前面介绍过build和MAKE的值,因此line 1047的形式为

$(Q)make -f ./scripts/Makefile.build obj=.

./scripts/Makefile.build文件中的目标为


line 8 __build:


目标__build在./scripts/Makefile.build后面内容中被重载


line 95 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
line 96    $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
line 97    $(subdir-ym) $(always)

line 98    @:


        KBUILD_BUILTIN赋值的地方在源码根目录Makefile的line 318 KBUILD_BUILTIN := 1,后续赋值的语句由于相关变量值的原因都不会生效


        KBUILD_MODULES赋值的地方在源码根目录Makefile的line 338 KBUILD_MODULES := 1,同样由于相关变量值的原因,其它赋值语句都不会生效。


                                    

则目标__build展开形式为


__build: $(builtin-target) $(lib-target) $(extra-y) $(obj-m) $(modorder-target) $(subdir-ym) $(always)
@:
                                   

由于目标__build的依赖中只有always有值(参见下述<<__build的依赖的分析>>),则目标__build形式为


__build: $(always)

@:


命令部分中的“@”表示取消回显
命令部分中的“:”是shell的内建命令,表示不做任何事


4.2.1.2.1.1.1 __build的依赖的分析

因为源码根目录Makefile中目标prepare0规则如下


line 1046 prepare0: archprepare gcc-plugins

line 1047     $(Q)make -f ./scripts/Makefile.build obj=.


所以在./scripts/Makefile.build文件中,


line 5 src := .

line 42 kbuild-dir := ./. (srctree的值参见前述内容)

line 43 kbuild-file := ././Kbuild (./.目录下存在Kbuild文件)
line 44 include ././Kbuild

line 53 include scripts/Makefile.lib 


在文件././Kbuild文件中,对always赋值的位置


line 38 bounds-file := include/generated/bounds.h
line 39
line 40 always  := $(bounds-file) 
line 73 offsets-file := include/generated/asm-offsets.h
line 74
line 75 always  += $(offsets-file)

line 91 always += missing-syscalls

在文件scripts/Makefile.lib中对always赋值的地方在


line 75 always      := $(addprefix $(obj)/,$(always))


最终,always的值为"./include/generated/bounds.h ./include/generated/asm-offsets.h ./missing-syscalls"
                                            
__build的其它依赖综合分析././Kbuild,scripts/Makefile.lib,scripts/Makefile.build后可以很容易的知道为空值
     

always各成员生成规则在源码根目录的Kbuild中:


line 48 $(obj)/$(bounds-file): kernel/bounds.s FORCE

line 49     $(call filechk,offsets,__LINUX_BOUNDS_H__)


line 84 $(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE

line 85     $(call filechk,offsets,__ASM_OFFSETS_H__)


line 97 missing-syscalls: scripts/checksyscalls.sh $(offsets-file) FORCE
line 98     $(call cmd,syscalls)

4.2.1.2.2 scripts

scripts的生成过程,与prepare类似,不再花费过多篇幅分析。

4.2.1.2.3 目标$(vmlinux-dirs)对应的命令的分析

源码根目录Makefile line 1002 $(Q)$(MAKE) $(build)=$@执行流程分析 (注:以arch/x86为例分析)

line 1002行展开部分变量后形式如下:


$(Q)make -f ./scripts/Makefile.build obj=$@


$(vmlinux-dirs)的值有多个成员,根据$@的含义及用法,选取其中一个值来进行说明。

例如arch/x86,则line 1002展开后形式为


$(Q)make -f ./scripts/Makefile.build obj=arch/x86

./scripts/Makefile.build的目标为

line 8 __build:

目标__build在后面内容中被重载

line 95 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
line 96    $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
line 97    $(subdir-ym) $(always)
line 98   @:


        KBUILD_BUILTIN赋值的地方在源码根目录Makefile的line 318 KBUILD_BUILTIN := 1,后续赋值的语句由于相关变量值的原因都不会生效


        KBUILD_MODULES赋值的地方在源码根目录Makefile的line 338 KBUILD_MODULES := 1,同样由于相关变量值的原因,其它赋值语句都不会生效。

                           
则目标__build展开形式为


__build: $(builtin-target) $(lib-target) $(extra-y) $(obj-m) $(modorder-target) $(subdir-ym) $(always)

@:


__build的依赖$(builtin-target)参见下述<<builtin-target值的来源>>,其它依赖的值也可参照$(builtin-target)的赋值过程进行类推来确认。

命令部分中的“@”表示取消回显
命令部分中的“:”是shell的内建命令,表示不做任何事

4.2.1.2.3.1  builtin-target值的来源
                            

源码根目录Makefile line 1002行在以arxh/x86为例展开时形式如下


$(Q)make -f ./scripts/Makefile.build obj=arch/x86


因此在./scripts/Makefile.build文件中,


line 5 src := arch/x86
line 42 kbuild-dir := ./arch/x86 (srctree的值参见前述内容)
line 43 kbuild-file := ./arch/x86/Kbuild (./arch/x86目录下存在Kbuild文件)

line 44 include ./arch/x86/Kbuild


       在文件./arch/x86/Kbuild文件中,对obj-y,obj-*赋值(*的值根据内核相关配置项来决定)的位置在文件./scripts/Makefile.build中(这个文件由命令行引入:$(Q)make -f ./scripts/Makefile.build obj=arch/x86),


line 53 include scripts/Makefile.lib


文件scripts/Makefile.lib中


line 42 obj-y       := $(patsubst %/, %/built-in.o, $(obj-y)) 
line 78 obj-y       := $(addprefix $(obj)/,$(obj-y)) (obj的值为arch/x86,由命令行传入:$(Q)make -f ./scripts/Makefile.build obj=arch/x86)


文件scripts/Makefile.build中


line 87 ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
line 88 builtin-target := $(obj)/built-in.o

line 89 endif


obj-y变量为非空值(obj-m,obj-,subdir-m,lib-target是否有值可参照上述obj-y的赋值过程确认),因此scripts/Makefile.build中
                                        

line 88 builtin-target := arch/x86/built-in.o


4.2.1.2.3.2 $(builtin-target)的生成过程

$(builtin-target)有值,则scripts/Makefile.build文件中line 429 ~ line 451有效


447 $(builtin-target): $(obj-y) FORCE
448     $(call if_changed,link_o_target)


       obj-y变量的值可查看前述<<builtin-target值的来源>>章节。obj-y有多个值,以kernel目录为例说明(注:源码根目录Makefile line 1002 $(Q)$(MAKE) $(build)=$@执行流程以arch/x86为例分析)。


       在经过arch/x86/Kbuild,scripts/Makefile.lib(这两个文件的引入位置参看<<builtin-target值的来源>>)的处理后,obj-y中与"kernel/"相关的部分变为了arch/x86/kernel/built-in.o,则目标$(buildin-target)规则的部分形式为


arch/x86/built-in.o: arch/x86/kernel/built-in.o

$(call if_changed,link_o_target)


而在scripts/Makefile.lib中,


line 42 obj-y       := $(patsubst %/, %/built-in.o, $(obj-y)) 

line 63 subdir-obj-y := $(filter %/built-in.o, $(obj-y))


那么变量obj-y中包含的kernel/built-in.o,变量subdir-obj-y中也包含。在经过scripts/Makefile.lib中下述语句的处理后,


line 81 subdir-obj-y    := $(addprefix $(obj)/,$(subdir-obj-y))


       subdir-obj-y中包含了值arch/x86/kernel/built-in.o(obj的值由命令行引入:$(Q)make -f ./scripts/Makefile.build obj=arch/x86,参见前述章节<<builtin-target值的来源>>)

在scripts/Makefile.build中,有下述目标


line 424 $(sort $(subdir-obj-y)): $(subdir-ym) ;


对于arch/x86/kernel/built-in.o来说,line 424行的规则变为了如下形式


arch/x86/kernel/built-in.o:$(subdir-ym);


这样一来,scripts/Makefile.build文件中下述目标的建立过程就可以继续探索了。


arch/x86/built-in.o: arch/x86/kernel/built-in.o(对应于line 447 $(builtin-target): $(obj-y) FORCE)

$(call if_changed,link_o_target)


在文件scripts/Makefile.build中,下述行定义了目标subdir-ym的建立方法


line 552 $(subdir-ym):
line 553     $(Q)$(MAKE) $(build)=$@


subdir-ym的值定义于文件scripts/Makefile.lib的下述行


line 38 __subdir-y  := $(patsubst %/,%,$(filter %/, $(obj-y)))
line 39 subdir-y    += $(__subdir-y)
line 40 __subdir-m  := $(patsubst %/,%,$(filter %/, $(obj-m)))
line 41 subdir-m    += $(__subdir-m)
line 44 
line 45 # Subdirectories we need to descend into
line 46 
line 47 subdir-ym   := $(sort $(subdir-y) $(subdir-m))
line 89 subdir-ym   := $(addprefix $(obj)/,$(subdir-ym))

在经过上述行处理后,subdir-ym中包含成员arch/x86/kernel,则文件scripts/Makefile.build中目标subdir-ym部分形式为

arch/x86/kernel:
@(Q)make -f $(srctree)/scripts/Makefile.build obj=arch/x86/kernel

       而上述目标subdir-ym的生成过程样式的语句,正是当前正在分析的内容。至此,以obj-y中成员kernel为例进行的分析就结束了,obj-y中的其它成员可以依此类推来进行分析。

       源码根目录Makefile中下述line 1001,line 1002规则中以obj=arch/x86为例进行的分析也结束了,obj中的其它成员,也可依据上述内容来进行分析。

line 1001 $(vmlinux-dirs): prepare scripts
line 1002     $(Q)$(MAKE) $(build)=$@

源码根目录Makefile line 1002 $(Q)$(MAKE) $(build)=$@执行流程的分析到这里也就结束了。

4.3 处理vmlinux的依赖$(vmlinux-deps)

在章节<<处理vmlinux的依赖vmlinux_prereq>>中,已经介绍了对$(vmlinux-deps)的处理,这里不再进行说明。

4.4 vmlinux链接过程

vmlinux的链接命令位于源码根目录Makefile中:


line 982 vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE

line 983     +$(call if_changed,link-vmlinux)


if_changed定义在文件scripts/Kbuild.include的下述位置


line 260 if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
line 261     @set -e;                                                             \
line 262     $(echo-cmd) $(cmd_$(1));                                             \
line 263     printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)


注:源代码根目录下的Makefile在下述位置引入了scripts/Kbuild.include


line 346 include scripts/Kbuild.include


link-vmlinux命令定义在源码根目录Makefile的下述位置

line 978     cmd_link-vmlinux =                                                 \
line 979     $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) ;       \
line 980     $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)

       由上述源码根目录Makefile line 982行及line 979行可知,链接vmlinux过程中执行了shell脚本scripts/link-vmlinux.sh,在脚本内的函数vmlinux_link将vmlinux所需的文件链接为了一个整体,期间使用了ld的配置文件arch/x86/kernel/vmlinux.lds。配置文件arch/x86/kernel/vmlinux.lds是在处理目标$(vmlinux-dirs)过程中生成的。


4.5 bzImage生成过程分析


目标bzImage的规则位于arch/x86/Makefile文件:


line 276 bzImage: vmlinux
line 277 ifeq ($(CONFIG_X86_DECODER_SELFTEST),y)
line 278     $(Q)$(MAKE) $(build)=arch/x86/tools posttest
line 279 endif
line 280     $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
line 281     $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
line 282     $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@

目标bzImage的生成命令中,主要关注


line 280     $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)

其中


boot变量定义在arch/x86/Makefile的


line 264 boot := arch/x86/boot


KBUILD_IMAGE变量定义在arch/x86/Makefile的


line 274 KBUILD_IMAGE := $(boot)/bzImage


build变量的值在前述内容已经介绍过,因此line 280行形式如下


line 280     $(Q)make -f ./scripts/Makefile.build obj=arch/x86/boot/ arch/x86/boot/bzImage


由前述章节<<prepare0>>的分析可知line 280会引入文件arch/x86/boot/Makefile。


在arch/x86/boot/Makefile文件中,定义了目标arch/x86/boot/bzImage


line 75 quiet_cmd_image = BUILD   $@
line 76 cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
line 77                    $(obj)/zoffset.h $@
line 78 
line 79 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
line 80     $(call if_changed,image)
line 81     @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'


       由上述arch/x86/boot/Makefile文件的line 75 ~ line 81行可知,bzImage是由arch/x86/boot/tools/build程序处理文件arch/x86/boot/setup.bin,arch/x86/boot/vmlinux.bin,arch/x86/boot/zoffset.h后生成的。


4.5.1 arch/x86/boot/setup.bin的生成

在文件arch/x86/boot/Makefile中有如下内容


line 107 $(obj)/setup.bin: $(obj)/setup.elf FORCE
line 108     $(call if_changed,objcopy)


line 103 $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE

line 104     $(call if_changed,ld)


line 87 SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))


line 33 setup-y     += a20.o bioscall.o cmdline.o copy.o cpu.o cpuflags.o cpucheck.o            

line 34 setup-y     += early_serial_console.o edd.o header.o main.o memory.o                    
line 35 setup-y     += pm.o pmjump.o printf.o regs.o string.o tty.o video.o                     
line 36 setup-y     += video-mode.o version.o                                                   
line 37 setup-$(CONFIG_X86_APM_BOOT) += apm.o             


line 43 setup-y     += video-vga.o

line 44 setup-y     += video-vesa.o                                                             
line 45 setup-y     += video-bios.o           


上述语句中,$(src)/setup.ld=arch/x86/boot/setup.ld,而setup.ld中描述了setup.bin中各个段的分布。

由上述语句,可以很容易的知道setup.bin的生成过程。


4.5.2 arch/x86/boot/vmlinux.bin的生成


在文件arch/x86/boot/Makefile中,有如下内容:


line 84 $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
line 85     $(call if_changed,objcopy)
line 110 $(obj)/compressed/vmlinux: FORCE
line 111     $(Q)$(MAKE) $(build)=$(obj)/compressed $@


由前述关于build的内容可知arch/x86/boot/Makefile的line 111形式如下


line 111     $(Q)make -f ./scripts/Makefile.build obj=arch/x86/boot/compressed arch/x86/boot/compressed/vmlinux


       由前述章节<<prepare0>>可知arch/x86/boot/Makefile的line 111行会引入文件arch/x86/boot/compressed/Makefile。下面会介绍依赖$(obj)/compressed/vmlinux,即arch/x86/boot/compressed/vmlinux的生成过程。在生成$arch/x86/boot/compressed/vmlinux后,会调用函数cmd_objcopy(位于文件scripts/Makefile.lib的line 268行,scripts/Makefile.lib在文件./scripts/Makefile.build文件中引入)来生成$(obj)/vmlinux.bin,即arch/x86/boot/vmlinux.bin


4.5.2.1  arch/x86/boot/compressed/vmlinux生成过程

在文件arch/x86/boot/compressed/Makefile中,有如下内容:


line 104 $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
line 105     $(call if_changed,check_data_rel)
line 106     $(call if_changed,ld)


line  71 vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \

line  72     $(obj)/string.o $(obj)/cmdline.o $(obj)/error.o \
line  73     $(obj)/piggy.o $(obj)/cpuflags.o


除了$(obj)/piggy.o外,其它的文件在目录$(obj)下都有对应的源文件,因此可以很容易的知道除piggy.o外其它文件的生成过程。

在文件arch/x86/boot/compressed/Makefile中,有如下内容:


line 143 quiet_cmd_mkpiggy = MKPIGGY $@
line 144       cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false ) 
line 147 $(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE
line 148     $(call if_changed,mkpiggy)


line 136 suffix-$(CONFIG_KERNEL_GZIP)    := gz

line 137 suffix-$(CONFIG_KERNEL_BZIP2)   := bz2
line 138 suffix-$(CONFIG_KERNEL_LZMA)    := lzma
line 139 suffix-$(CONFIG_KERNEL_XZ)  := xz
line 140 suffix-$(CONFIG_KERNEL_LZO)     := lzo
line 141 suffix-$(CONFIG_KERNEL_LZ4)     := lz4


line 123 $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) FORCE

line 124     $(call if_changed,gzip)
line 125 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
line 126     $(call if_changed,bzip2)
line 127 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
line 128     $(call if_changed,lzma)
line 129 $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
line 130     $(call if_changed,xzkern)
line 131 $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE
line 132     $(call if_changed,lzo)
line 133 $(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCE
line 134     $(call if_changed,lz4)


line 120 vmlinux.bin.all-y := $(obj)/vmlinux.bin

line 121 vmlinux.bin.all-$(CONFIG_X86_NEED_RELOCS) += $(obj)/vmlinux.relocs


line 109 $(obj)/vmlinux.bin: vmlinux FORCE

line 110     $(call if_changed,objcopy)


由上述语句可知arch/x86/boot/compressed/vmlinux的生成过程。


       上述line 109中的依赖vmlinux,是源代码根目录中生成的vmlinux(生成arch/x86/boot/compressed/vmlinux过程中的所有make命令没有选项-C,因此都是在源代码根目录下执行的,所以line 109中依赖的vmlinux是源代码根目录中的vmlinux),与arch/x86/boot/compressed/vmlinux不同。由上述语句可知,$(obj)/piggy.S是由$(obj)/vmlinux.bin.$(suffix-y)转化而来,进而由$(obj)/piggy.S生成了$(obj)/piggy.o 

        

至此,整个Makefile的分析就结束了。



bzImage组成概览


arch/x86/boot/bzImage

|

|

|--arch/x86/boot/setup.bin   ...........arch/x86/boot目录下文件编译得到

|

|

|--arch/x86/boot/vmlinux.bin

*

*

*--arch/x86/boot/compressed/vmlinux

|

|

|--arch/x86/boot/compressed目录下相关文件

|

|

|--piggy.o

*

*

*--arch/x86/boot/compressed/vmlinux.bin.$(suffix-y)     ........后缀名取决于配置的压缩方式

|

|

|--源代码根目录中的vmlinux



猜你喜欢

转载自blog.csdn.net/dwdwdw2/article/details/78587782