Linux系统移植:Kernel 顶层 Makefile(下)

Linux系统移植:Kernel 顶层 Makefile(下)
继续分析 Linux 内核源码顶层 Makefile 执行过程

一、make defconfig 过程
与 uboot 的顶层 makefile 相同,在编译源码前,要用 make xxx_defconfig 配置 Linux 内核,代码首先配置

config-targets
mixed-targets
dot-config
这三个参数

这段代码执行后,值改变如下:

config-targets= 1
mixed-targets= 0
dot-config= 1
1
2
3
后面的代码就是根据这三个值来选择执行,config-targets=1 执行代码如下:

这段代码主要的就是引用 arch/arm/Makefile 这个文件(zImage、uImage 等文件就是由 arch/arm/Makefile 生成),然后导出 KBUILD_DEFCONFIG、KBUILD_KCONFIG,

然后因为 “%config” 与前面的匹配,因此执行后面的代码,“%config” 依赖于 scripts_basic、outputmakefile 和 FORCE

scripts_basic 代码如下:

build 定义在文件 scripts/Kbuild.include 中,值为 build := -f $(srctree)/scripts/Makefile.build obj

展开就是:

scripts_basic:
    make -f ./scripts/Makefile.build obj=scripts/basic 
    rm -f . tmp_quiet_recordmcount 
1
2
3
所以 %config 下面的命令展开就是:

make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
1
编译 xxx_defconfig

二、Makefile.build 脚本分析
所以一中最终会执行两个脚本

#scripts_basic 依赖执行的
make -f ./scripts/Makefile.build obj=scripts/basic
#%config 执行的
make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
1
2
3
4
他们都执行了 Makefile.build 这个脚本,这两个 Makefile.build 执行有不同的效果:

scripts_basic 目标的作用就是编译出 scripts/basic/fixdep 和 scripts/basic/bin2c 这两个软件

而第二行代码会与下面的展开代码进行匹配

%_defconfig: scripts/kconfig/conf
    scripts/kconfig/conf --defconfig=arch/arm/configs/%_defconfig Kconfig
1
2
代码依赖与 scripts/kconfig/conf,会编译 scripts/kconfig/conf.c 生成 conf 软件,此软件就会将 %_defconfig 中的配置输出到.config 文件中,最终生成 Linux kernel 根目录下的.config 文件

三、make 过程
输入 make 后默认编译全部,代码如下:

然后 all 依赖于 vmlinux

vmlinux 依赖 scripts/link-vmlinux.sh $(vmlinux-deps) FORCE,vmlinux-deps 定义如下:

vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
1
其中参数在前面都有定义

KBUILD_VMLINUX_INIT= $(head-y) $(init-y)
KBUILD_VMLINUX_MAIN = $(core-y) $(libs-y) $(drivers-y) $(net-y)
KBUILD_LDS= arch/$(SRCARCH)/kernel/vmlinux.lds
1
2
3
其中 SRCARCH=arm,所以 vmlinux 实际的依赖为:

scripts/link-vmlinux.sh、$(head-y) 、$(init-y)、$(core-y) 、$(libs-y) 、$(drivers-y) 、$(net-y)、arch/arm/kernel/vmlinux.lds 和 FORCE
1
head-y
定义在文件 arch/arm/Makefile 中

head-y := arch/arm/kernel/head$(MMUEXT).o
1
不使能 MMU 的话 MMUEXT=-nommu,如果使能 MMU 的话为空,这里使能了

init-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
1
2
3
libs-y
相关代码如下:

libs-y := lib/
......
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)
1
2
3
4
5
在 arch/arm/Makefile 文件下:

libs-y := arch/arm/lib/ $(libs-y)
1
所以 libs-y 最终值如下:

libs-y = arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o
1
core-y
顶层 Makefile 中有如下代码

core-y := usr/
...
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
1
2
3
在 arch/arm/Makefile 中对 core-y 进行追加

代码根据不同的配置向 core-y 追加不同的值,如使能 VFP 的话就会在 .config 中有 CONFIG_VFP=y 这一行,那么 core-y 就会追加 arch/arm/vfp/

然后 makefile 后面的代码还有追加

core-y := $(patsubst %/, %/built-in.o, $(core-y))
1
如果使能 CONFIG_VFP,最终参数就如下:

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
1
2
3
4
5
6
7
8
9
这些变量都是一些 built-in.o 或.a 等文件,将相应目录中的源码文件进行编译,在各自目录下生成 built-in.o 文件,有些生成了.a 库文件,最终将这些 built-in.o 和.a 文件进行链接即可形成 ELF 格式的可执行文件,也就是 vmlinux,链接文件为 arch/arm/kernel/vmlinux.lds,链接过程是由 shell 脚本 scripts/link-vmlinux.sh 来完成

四、built-in.o 文件编译生成过程
上节知道 built-in.o 和 .a 库文件由 link-vmlinux.sh 文件链接后生成 vmlinux,下面看一下 built-in.o 如何编译生成的

因为 vmliux 依赖 vmlinux-deps,

vmlinux-deps= $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
1
KBUILD_LDS 是链接脚本,KBUILD_VMLINUX_INIT 和 KBUILD_VMLINUX_MAIN 是各个子目录下的 built-in.o、.a 文件,最终值如下:

makefile 有个函数对 vmlinux-deps 的字符串列表进行排序,去掉重复的单词,函数依赖于 vmlinux-dirs

(sort $(vmlinux-deps)): $(vmlinux-dirs)
1
vmlinux-dirs 是一个关键参数

vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
             $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
             $(net-y) $(net-m) $(libs-y) $(libs-m)))
1
2
3
保存参数如下:

同时顶层 Makefile 中有如下代码:

vmlinux-dirs 依赖 prepare 和 scripts,然后执行

make -f ./scripts/Makefile.build obj=$@
1
正是这个函数将 vmlinux-dirs 中的这些目录全部带入到命令中编译生成 .o 文件

五、 make zImage 过程
上文提到的 vmlinux,除此之外还有几个比较重要的文件,简单说明一下他们:

vmlinux:

vmlinux 是编译出来的最原始的内核文件,未经过压缩处理,如正点原子提供的 Linux 源码编译出来的 vmlinux 差不多有 16MB

Image:

Image 是 Linux 内核镜像文件,仅包含可执行的二进制数据,是使用 objcopy 取消掉 vmlinux 中的一些其他信息获得的

zImage:

zImage 是经过 gzip 压缩后的 Image

uImage:

uImage 是老版本 uboot 用的下载镜像文件,uImag 是在 zImage 前面加了一个长度为 64 字节的头部信息,这个头信息描述了该镜像文件的类型、加载位置、生成时间、大小等信息,目前新的 uboot 已经支持了zImage 启动,不在需要 uImage

在 arch/arm/Makefile 中有如下代码

变量 BOOT_TARGETS 输出 zImage,Image,xipImage 等镜像文件,其依赖于 vmlinux,具体编译指令展开后如下:

make -f ./scripts/Makefile.build obj=arch/arm/boot MACHINE=arch/arm/boot/zImage
————————————————
版权声明:本文为CSDN博主「Top嵌入式」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45396672/article/details/123264161

你可能感兴趣的:(linux,服务器,运维)