前言
写文章的目的是想通过记录自己的学习过程,以便以后使用到相关的知识点可以回顾和参考。
编译流程
其实内核的编译跟uboot编译差不多,uboot的编写方式就是参考内核源码来的,等下分析的顶层Makefile就能看出来了,下面是内核编译的流程:
1、make distclean ------第一次编译时需清理一下工程文件
2、make xxx_defconfig------xxx一般是半导体厂家根据soc的架构或者名称命名的,xxx_defconfig是半导体厂家提供的内核默认配置文件,在arch\arm\configs中3、make menuconfig------在默认配置基础上,通过图形化界面追加一些配置选项
4、make all------编译生成zImage,会生成在arch\arm\boot中
其中,配置后会在内核根文件目录下生成一个.config文件,里面就是具体的配置的内容。
分析流程
分析流程之前先理解一下各层Makefile的作用和区别
一、清理工程
make distclean跟清理uboot工程一样,通常是第一个编译时需要清理,如果后续通过make menuconfig图形化界面追加配置了内核,千万不要执行这个清理命令,不然配置都会被清掉。
二、配置内核
在arch\arm\configs中有很多以xxx_defconfig命名的文件,选择一个跟自己板子相似的配置文件,然后使用命令make xxx_defconfig进行配置
它的具体执行在顶层Makefile中的体现如下:
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
build 定义在文件 scripts/Kbuild.include 中,值为 build := -f $(srctree)/scripts/Makefile.build obj
obj,展开就是:make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
Makefile.build 会读取 scripts/kconfig/Makefile 中的内容,此文件中有如下内容:
%_defconfig: $(obj)/conf
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
目标%_defconfig 与 xxx_defconfig 匹配,所以会执行这条规则,将其展开就是:
%_defconfig: scripts/kconfig/conf
scripts/kconfig/conf --defconfig=arch/arm/configs/%_defconfig Kconfig
%_defconfig依赖scripts/kconfig/conf,所以会编译scripts/kconfig/conf.c生成conf这个软件。
此软件就会将%_defconfig 中的配置输出到.config 文件中,最终生成内核根目录下
的.config 文件。
二、编译内核
通过顶层Makefile可以知道all依赖vmlinux,而vmlinux就是编译出来的内核文件了,但是它是ELF格式的文件,在arch/arm/Makefile中需要把它
转换成最终的zImage二进制内核镜像文件。下面分析下vmlinux是如何生成的。
首先在顶层Makefile中找到vmlinux
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
+$(call if_changed,link-vmlinux)
依赖于$(vmlinux-deps),在顶层Makefile中可以知道
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
将其展开得:
vmlinux-deps := arch/$(SRCARCH)/kernel/vmlinux.lds $(head-y) $(init-y) $(core-y) $(libs-y) $(drivers-y) $(net-y)
综上所述:
vmlinux依赖于:scripts/link-vmlinux.sh,FORCE,arch/$(SRCARCH)/kernel/vmlinux.lds
$(head-y) $(init-y) $(core-y) $(libs-y) $(drivers-y) $(net-y)
然后重点是这6个变量的值 $(head-y) $(init-y) $(core-y) $(libs-y) $(drivers-y) $(net-y)
我们可以通过顶层Makefile 和 arch/arm/Makefile把这6个变量展开得:
head-y = arch/arm/kernel/head.o
init-y = init/built-in.o
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
libs-y = arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o
drivers-y = drivers/built-in.o sound/built-in.o firmware/built-in.o
net-y = net/built-in.o
从上面可以知道这6个变量都是一些 built-in.o 或.a 等文件,这个和 uboot 一样,都是将相应目录中的源码文件进行编译,然后在各自目录下生成 built-in.o 文件,有些生成了.a 库文件。最终将这些 built-in.o 和.a 文件进行链接即可形成 ELF 格式的可执行文件,也就是 vmlinux!但是链接是需要链接脚本的,vmlinux 的依赖 arch/arm/kernel/vmlinux.lds 就是整个 Linux 的链接脚本。