Linux内核编译make做了什么?
执行make默认目标的依赖链如下:
1. include/config/auto.conf去匹配include/config/%.conf,执行其命令: $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig即make -f ./Makefile silentoldconfig, 该句执行与make x210ii_qt_defconfig相似 silentoldconfig匹配到%config,其依赖scripts_basic,生成fixdep docproc hash 再回到%config下执行$(Q)$(MAKE) $(build)=scripts/kconfig $@即make scripts/Makefile.build obj=scripts/kconfig silentoldconfig,其过程为Makefile.build 包含scripts/kconfig/Makefile,其包含了silentoldconfig目标,silentoldconfig又依赖于scripts/kconfig/conf, Makefile.host依据scripts/kconfig里的材料再次生成conf,回到执行silentoldconfig目标下的命令$< -s $(Kconfig) 即scripts/kconfig/conf -s arch/arm/Kconfig该命令根据.config和arch/arm/Kconfig生成include/config/auto.conf.cmd, include/config/auto.conf ,include/generated/autoconf.h
2. 回到include/config/kernel.release,该目标命令:
$(Q)echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" > $@,该句将版本信息输出到include/config/kernel.release,
3. 再回到prepare3,无命令;
4. 回到prepare2,无命令,
5. 到include/linux/version.h下执行$(call filechk,version.h)该句得到include/linux/version.h;
6. 再到include/generated/utsrelease.h下执行$(call filechk,utsrelease.h)得到include/generated/utsrelease.h;
7. 再回到prepare1,无命令;再到scripts_basic和上次功能一样;回到archprepare执行$(Q)$(MAKE) $(clean)=$(boot),该句产生include/generated/mach-types.h,该命令再arch/arm/Makefile中;
8. 回到prepare0 执行$(Q)$(MAKE) $(build)=. 即把当前目录传递给scripts/Makefile.build,则该makefile会包含根目录下的kbuild,根据该文件下的规则产生include/generated/bounds.h和include/generated/asm-offsets.h;
9. 回到prepare0 执行下一句$(Q)$(MAKE) $(build)=. missing-syscalls该句根据kbuild下的规则去执行scripts/checksyscalls.sh脚本,
10. 到scripts,开始执行scripts下的命令$(Q)$(MAKE) $(build)=$(@) 即make -f scripts/Makefile.host obj=script 先包含scripts下的Makefile默认执行目标__build其此时依赖链如下:
__build:
$(subdir-ym) $(always)
subdir-ym=scripts/mod always= scripts/kallsyms scripts/pnmtologo scripts/conmakehash
开始$(subdir-ym)的命令$(Q)$(MAKE) $(build)=$@即make -f scripts/Makefile.build obj=scripts/mod该命令先用scripts/mod/mk_elfconfig.c生成mk_elfconfig,再用mk_elfconfig生成mk_elfconfig.h,最后得到scripts/mod/modpost,
退出回到$(always)得到scripts/kallsyms scripts/pnmtologo scripts/conmakehash退出scripts
11. 接下来回到目标$(vmlinux-dirs)执行至关重要的一句话$(Q)$(MAKE) $(build)=$@首先我们来分析$(vmlinux-dirs)它包含 $(init-y) $(init-m) $(core-y) $(core-m) $(drivers-y) $(drivers-m) $(net-y) $(net-m) $(libs-y) $(libs-m) 基本也就是整个内核了,打印出来为:
vmlinux-dirs = init usr arch/arm/kernel arch/arm/mm arch/arm/common arch/arm/mach-s5pv210 arch/arm/plat-s5p arch/arm/plat-samsung arch/arm/vfp kernel mm fs ipc security crypto block drivers sound firmware net arch/arm/lib lib,$(Q)$(MAKE) $(build)=$@将其一一执行。举例:$@=init时:$(Q)$(MAKE) $(build)=$@即为make -f scripts/Makefile.build obj=init 将包含init/Makefile,其中定义了一些变量和一些规则导致__build的依赖为编入内核模式即builtin-target = init/built-in.o最后根据scripts/Makefile.build,和init/Makefile中的规则生成 init/built-in.o,执行完成退出。
12. 最后生成$(vmlinux-lds) vmlinux.o $(kallsyms.o) vmlinux,zimage
总结:
生成内核的过程:先做准备工作,目标$(vmlinux-dirs)的依赖prepare的scripts用于产生头文件的一些功能文件,接着对$(vmlinux-dirs)下文件有一一生成,最后生成$(vmlinux-lds) vmlinux.o $(kallsyms.o) vmlinux,zimage
关于文件生成机制:
主Makefile调用scripts/Makefile.build并且传入obj变量指明要编译的文件目录,scripts/Makefile.build中会包含obj变量的makefile或者kbuild,如果执行时未传入目标则会默认执行scripts/Makefile.build中的__build,该目标有三种依赖模式:编入模式(链接到内核),非编入模式,编译子文件和主机编译模式,每种依赖模式的确定要根据obj中Makefile定义的变量来确定,编译规则则是按照scripts/Makefile.build,scripts/Makefile.host,scripts/Makefile.lib,obj/Makefile等来确定;如果执行时指定目标,则obj下的makefile必然有相应的目标与之对应,再根据scripts/Makefile.build,scripts/Makefile.host,scripts/Makefile.lib,obj/Makefile中的规则编译。