linux 顶层makefile源码剖析三 make 过程

41 篇文章 6 订阅
22 篇文章 2 订阅
125 PHONY := _all
126 _all:
......
192 PHONY += all
193 ifeq ($(KBUILD_EXTMOD),)
194 _all: all
195 else
196 _all: modules
197 endif
......
608 all: vmlinux

第 126 行, _all 是默认目标,如果使用命令“make”编译 Linux 的话此目标就会被匹配。
第 193 行,如果 KBUILD_EXTMOD 为空的话 194 行的代码成立。
第 194 行,默认目标_all 依赖 all。
第 608 行,目标 all 依赖 vmlinux,所以接下来的重点就是 vmlinux!
在这里插入图片描述
从第 920 行可以看出目标 vmlinux 依赖 scripts/link-vmlinux.sh $(vmlinux-deps) FORCE。第912 行定义了 vmlinux-deps,值为:

vmlinux-deps= $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

第 905 行, KBUILD_VMLINUX_INIT= $(head-y) $(init-y)。
第 906 行, KBUILD_VMLINUX_MAIN = $(core-y) $(libs-y) $(drivers-y) ( n e t − y ) 。 第 907 行 , K B U I L D L D S = a r c h / (net-y)。 第 907 行, KBUILD_LDS= arch/ (nety)907KBUILDLDS=arch/(SRCARCH)/kernel/vmlinux.lds,其中 SRCARCH=arm,因此 KBUILD_LDS= arch/arm/kernel/vmlinux.lds。
综上所述, vmlinux 的依赖为: scripts/link-vmlinux.sh、 $(head-y) 、 $(init-y)、 ( c o r e − y ) 、 (core-y) 、 (corey)(libs-y) 、 $(drivers-y) 、 $(net-y)、 arch/arm/kernel/vmlinux.lds 和 FORCE。
第 933 行的命令用于链接生成 vmlinux。

1、 head-y

head-y 定义在文件 arch/arm/Makefile 中,内容如下:

135 head-y := arch/arm/kernel/head$(MMUEXT).o

当不使能 MMU 的话 MMUEXT=-nommu,如果使能 MMU 的话为空,因此 head-y 最终的值为:

head-y = arch/arm/kernel/head.o

2、 init-y、 drivers-y 和 net-y

558 init-y := init/
559 drivers-y := drivers/ sound/ firmware/
560 net-y := net/
......
896 init-y := $(patsubst %/, %/built-in.o, $(init-y))
898 drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
899 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

3、 libs-y

libs-y 基本和 init-y 一样,在顶层 Makefile 中存在如下代码:

561 libs-y := lib/
......
900 libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
901 libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
902 libs-y := $(libs-y1) $(libs-y2)

libs-y 应该等于“lib.a built-in.o”,这个只正确了一部分!因为在 arch/arm/Makefile 中会向 libs-y 中追加一些值

286 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

4、 core-y

core-y 和 init-y 也一样,在顶层 Makefile 中有如下代码:

#顶层 Makefile 代码段
532 core-y := usr/
......
887 core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/

但是在 arch/arm/Makefile 中会对 core-y 进行追加,代码如下:

arch/arm/Makefile 代码段
269 core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
270 core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
271 core-$(CONFIG_VFP) += arch/arm/vfp/
272 core-$(CONFIG_XEN) += arch/arm/xen/
273 core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/
274 core-$(CONFIG_VDSO) += arch/arm/vdso/
275
276 # If we have a machine-specific directory, then include it in thebuild.
277 core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
278 core-y += arch/arm/probes/
279 core-y += arch/arm/net/
280 core-y += arch/arm/crypto/
281 core-y += arch/arm/firmware/
282 core-y += $(machdirs) $(platdirs)

第 269~274 行根据不同的配置向 core-y 追加不同的值,比如使能 VFP 的话就会在.config中有CONFIG_VFP=y 这一行,那么 core-y 就会追加“arch/arm/vfp/”。
第 277~282 行就是对 core-y 直接追加的值。
在顶层 Makefile 中有如下一行:

顶层 Makefile 代码段
897 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

最终将这些 built-in.o 和.a 文件进行链接即可形成 ELF 格式的可执行文件,也就是 vmlinux!但是链接是需要连接脚本的,
vmlinux 的依赖 arch/arm/kernel/vmlinux.lds 就是整个 Linux 的链接脚本。

顶层 Makefile 代码段第 933 行的命令“ + ( c a l l i f c h a n g e d , l i n k − v m l i n u x ) ” 表 示 将 (call if_changed,link-vmlinux)”表示将 (callifchanged,linkvmlinux)(call if_changed,link-vmlinux)的结果作为最终生成 vmlinux 的命令,前面的“+”表示该命令结果不可忽略。 $(call if_changed,link-vmlinux)是调用函数 if_changed, link-vmlinux 是函数 if_changed 的参数,函数 if_changed 定义在文件 scripts/Kbuild.include 中

247 if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
248 @set -e; \
249 $(echo-cmd) $(cmd_$(1)); \
250 printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

any-prereq 用于检查依赖文件是否有变化,如果依赖文件有变化那么 any-prereq 就不为空,否则就为空。 arg-check 用于检查参数是否有变化,如果没有变化那么 arg-check 就为空。
第 248 行,“@set -e”告诉 bash,如果任何语句的执行结果不为 true(也就是执行出错)的话就直接退出。
第 249 行, $(echo-cmd)用于打印命令执行过程,比如在链接 vmlinux 的时候就会输出“LINK vmlinux”。 KaTeX parse error: Expected group after '_' at position 5: (cmd_̲(1))中的 ( 1 ) 表 示 参 数 , 也 就 是 l i n k − v m l i n u x , 因 此 (1)表示参数,也就是 link-vmlinux,因此 (1)linkvmlinux(cmd_$(1))表示执行 cmd_link-vmlinux 的内容。 cmd_link-vmlinux 在顶层 Makefile 中有如下所示定义:

914 # Final link of vmlinux
915 cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)
916 quiet_cmd_link-vmlinux = LINK $@

第 915 行就是 cmd_link-vmlinux 的值,其中 CONFIG_SHELL=/bin/bash, $<表示目标 vmlinux的第一个依赖文件,根据示例代码 35.5.3.2 可知,这个文件为 scripts/link-vmlinux.sh。LD= arm-linux-gnueabihf-ld -EL, LDFLAGS 为空。 LDFLAGS_vmlinux 的值由顶层 Makefile 和arch/arm/Makefile 这两个文件共同决定最终 LDFLAGS_vmlinux=-p --no-undefined -X --picveneer --build-id。因此 cmd_link-vmlinux 最终的值为:

`cmd_link-vmlinux = /bin/bash scripts/link-vmlinux.sh arm-linux-gnueabihf-ld -EL -p --noundefined -X --pic-veneer --build-id`

cmd_link-vmlinux 会调用 scripts/link-vmlinux.sh 这个脚本来链接出 vmlinux!
在 linkvmlinux.sh 中有如下所代码:

scripts/link-vmlinux.sh 代码段
51 vmlinux_link()
52 {
53 local lds="${objtree}/${KBUILD_LDS}"
54
55 if [ "${SRCARCH}" != "um" ]; then
56 ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \
57 -T ${lds} ${KBUILD_VMLINUX_INIT} \
58 --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
59 else
60 ${CC} ${CFLAGS_vmlinux} -o ${2} \
61 -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT} \
62 -Wl,--start-group \
63 ${KBUILD_VMLINUX_MAIN} \
64 -Wl,--end-group \
65 -lutil ${1}
66 rm -f linux
67 fi
68 }
......
216 info LD vmlinux
217 vmlinux_link "${kallsymso}" vmlinux

vmliux_link 就是最终链接出 vmlinux 的函数,第 55 行判断 SRCARCH 是否等于“um”,如果不相等的话就执行 56~58 行的代码。因为 SRCARCH=arm,因此条件成立,执行 56~58 行的代 码 。 这 三 行 代 码 就 应 该 很 熟 悉 了 ! 就 是 普 通 的 链 接 操 作 , 连 接 脚 本 为lds= ./arch/arm/kernel/vmlinux.lds , 需 要 链 接 的 文 件 由 变 量 KBUILD_VMLINUX_INIT 和KBUILD_VMLINUX_MAIN 来决定,这两个变量在示例代码 35.5.3.2 中已经讲解过了。
第 217 行调用 vmlinux_link 函数来链接出 vmlinux。
使用命令“make V=1”编译 Linux,
在这里插入图片描述
make 的过程,重点就是将各个子目录下的 built-in.o、 .a 等文件链接在一起,最终生成 vmlinux 这个 ELF 格式的可执行文件。链接脚本为 arch/arm/kernel/vmlinux.lds,链接过程是由shell脚本scripts/link-vmlinux.s来完成的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值