博客已迁移,新博客地址:https://www.wxtechblog.com
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:allall:bzImagebzImage: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 253line 254 # suspend and hibernation supportline 255 drivers-$(CONFIG_PM) += arch/x86/power/line 256line 257 drivers-$(CONFIG_FB) += arch/x86/video/line 258line 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