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

Posted 嵌入式up笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

后面的代码就是根据这三个值来选择执行,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 

所以 %config 下面的命令展开就是:

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

编译 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

他们都执行了 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

代码依赖与 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)

其中参数在前面都有定义

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

其中 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
  • head-y

定义在文件 arch/arm/Makefile 中

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

不使能 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
  • 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)

在 arch/arm/Makefile 文件下:

libs-y := arch/arm/lib/ $(libs-y)

所以 libs-y 最终值如下:

libs-y = arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o
  • core-y

顶层 Makefile 中有如下代码

core-y := usr/
...
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/

在 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))

如果使能 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

这些变量都是一些 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)

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

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

(sort $(vmlinux-deps)): $(vmlinux-dirs)

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)))

保存参数如下:

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

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

make -f ./scripts/Makefile.build obj=$@

正是这个函数将 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

就是借助 scripts/Makefile.build 文件完成 vmlinux 到 zImage 的转换

以上是关于Linux系统移植:Kernel 顶层 Makefile(下)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

Linux系统移植:U-Boot 顶层 Makefile 分析(上)

Linux系统移植:U-Boot 顶层 Makefile 分析(下)

Linux系统移植:原厂 Kernel 移植到开发板

Linux系统移植:原厂 Kernel 移植到开发板