Linux内核顶层Makefile详解

直接参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81

本文仅作为个人笔记使用,方便进一步记录自己的实践总结。
前几章我们重点讲解了如何移植 uboot 到 I.MX6U-ALPHA 开发板上,从本章开始我们就开始学习如何移植 Linux 内核。同 uboot 一样,在具体移植之前,我们先来学习一下 Linux 内核的顶层 Makefile 文件,因为顶层 Makefile 控制着 Linux 内核的编译流程。

Linux 内核获取

关于 Linux 的起源以及发展历史,这里就不啰嗦了,网上相关的介绍太多了!即使写到这里也只是水一下教程页数而已,没有任何实际的意义。有限的时间还是放到有意义的事情上吧,Linux 由 Linux 基金会管理与发布,Linux 官网为:

The Linux Kernel Archives

所以你想获取最新的Linux 版本就可以在这个网站上下载,网站界面如图 35.1.1 所示:

从图 35.1.1 可以看出最新的稳定版 Linux 已经到了 5.1.4,大家没必要追新,因为 4.x 版本的 Linux 和 5.x 版本没有本质上的区别,5.x 更多的是加入了一些新的平台、新的外设驱动而已。NXP 会从 https://www.kernel.org 下载某个版本的 Linux 内核,然后将其移植到自己的 CPU上,测试成功以后就会将其开放给 NXP 的 CPU 开发者。开发者下载 NXP 提供的 Linux 内核,然后将其移植到自己的产品上。本章的移植我们就使用 NXP 提供的 Linux 源码,NXP 提供 Linux源码已经放到了开发板光盘中,路径为: 开发板光盘->1、例程源码->4、NXP 官方原版 Uboot和 Linux-> linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2

Linux 内核初次编译

编译内核之前需要先在 ubuntu 上安装 lzop 库,否则内核编译会失败!命令如下:

sudo apt-get install lzop

先看一下如何编译 Linux 源码,这里编译 I.MX6U-ALPHA 开发板移植好的 Linux 源码,已经放到了开发板光盘中,路径为:开发板光盘->1、例程源码-> 3、正点原子 Uboot 和 Linux 出厂源码-> linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2,注意,正点原子出厂系统在不断的更新,因此压缩包的名字可能不同,一切以实际为准!

在 Ubuntu 中新建名为" alientek_linux " 的 文 件夹 , 然 后 将 linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2 这个压缩包拷贝到前面新建的 alientek_linux 文件夹中并解压,命令如下:

tar -vxjf linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2

解压完成以后的 Linux 源码根目录如图 35.2.1 所示:

以 EMMC 核心板为例,讲解一下如何编译出对应的 Linux 镜像文件。新建名为"mx6ull_alientek_emmc.sh"的 shell 脚本,然后在这个 shell 脚本里面输入如下所示内容:

示例代码 35.2.1 mx6ull_alientek_emmc.sh 文件内容
1 #!/bin/sh
2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
4 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
5 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

使用 chmod 给予 mx6ull_alientek_emmc.sh 可执行权限,然后运行此 shell 脚本,命令如下:

./mx6ull_alientek_emmc.sh

编译的时候会弹出 Linux 图形配置界面,如图 35.2.2 所示:

Linux 的图行界面配置和 uboot 是一样的,这里我们不需要做任何的配置,直接按两下 ESC键退出,退出图形界面以后会自动开始编译 Linux。等待编译完成,完成以后如图 35.2.3 所示:

编译完成以后就会在 arch/arm/boot 这个目录下生成一个叫做 zImage 的文件,zImage 就是我们要用的 Linux 镜像文件。另外也会在 arch/arm/boot/dts 下生成很多.dtb 文件,这些.dtb 就是设备树文件。

编译 Linux 内核的时候可能会提示"recipe for target 'arch/arm/boot/compressed/piggy.lzo'failed",如图 35.2.4 所示:

图 35.2.4 中的错误提示 lzop 未找到,原因是没有安装 lzop 库,输入如下命令安装 lzop 库即可解决:

sudo apt-get install lzop

lzop 库安装完成以后在重新编译一下 Linux 内核即可。

看一下编译脚本 mx6ull_alientek_emmc.sh 的内容,文件内容如下:

示例代码 35.2.2 mx6ull_alientek_emmc.sh 文件内容
1 #!/bin/sh
2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
4 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
5 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

第 2 行,执行"make distclean",清理工程,所以 mx6ull_alientek_emmc.sh 每次都会清理一下工程。如果通过图形界面配置了 Linux,但是还没保存新的配置文件,那么就要慎重使用mx6ull_alientek_emmc.sh 编译脚本了,因为它会把你的配置信息都删除掉!

第 3 行,执行"make xxx_defconfig",配置工程。

第 4 行,执行"make menuconfig",打开图形配置界面,对 Linux 进行配置,如果不想每次编译都打开图形配置界面的话可以将这一行删除掉。

第 5 行,执行"make",编译 Linux 源码。

可以看出,Linux 的编译过程基本和 uboot 一样,都要先执行"make xxx_defconfig"来配置一下,然后在执行"make"进行编译。如果需要使用图形界面配置的话就执行"make menuconfig"。

Linux 工程目录分析

将正点原子提供的 Linux 源码进行解压,解压完成以后的目录如图 35.3.1 所示:

图 35.3.1 就是正点原子提供的未编译的 Linux 源码目录文件,我们在分析 Linux 之前一定要先在 Ubuntu 中编译一下 Linux,因为编译过程会生成一些文件,而生成的这些恰恰是分析Linux 不可或缺的文件。编译完成以后使用 tar 压缩命令对其进行压缩并使用 Filezilla 软件将压缩后的 uboot 源码拷贝到 Windows 下。

编译后的 Linux 目录如图 35.3.2 所示:

图 35.3.2 中重要的文件夹或文件的含义见表 35.3.1 所示:

表 35.3.1 中的很多文件夹和文件我们都不需要去关心,我们要关注的文件夹或文件如下:

1、arch 目录

这个目录是和架构有关的目录,比如 arm、arm64、avr32、x86 等等架构。每种架构都对应一个目录,在这些目录中又有很多子目录,比如 boot、common、configs 等等,以 arch/arm 为例,其子目录如图 35.3.3 所示:

图 35.3.3 是 arch/arm 的一部分子目录,这些子目录用于控制系统引导、系统调用、动态调频、主频设置等。arch/arm/configs 目录是不同平台的默认配置文件:xxx_defconfig,如图 35.3.4所示:

在 arch/arm/configs 中就包含有 I.MX6U-ALPHA 开发板的默认配置文件:imx_v7_defconfig,执行"make imx_v7_defconfig"即可完成配置。arch/arm/boot/dts 目录里面是对应开发平台的设备树文件,正点原子 I.MX6U-ALPHA 开发板对应的设备树文件如图 35.3.5 所示:

arch/arm/boot 目录下会保存编译出来的 Image 和 zImage 镜像文件,而 zImage 就是我们要用的 linux 镜像文件。

arch/arm/mach-xxx 目录分别为相应平台的驱动和初始化文件,比如 mach-imx 目录里面就是 I.MX 系列 CPU 的驱动和初始化文件。

2、block 目录

block 是 Linux 下块设备目录,像 SD 卡、EMMC、NAND、硬盘等存储设备就属于块设备,block 目录中存放着管理块设备的相关文件。

3、crypto 目录

crypto 目录里面存放着加密文件,比如常见的 crc、crc32、md4、md5、hash 等加密算法。

4、Documentation 目录

此目录里面存放着 Linux 相关的文档,如果要想了解 Linux 某个功能模块或驱动架构的功能,就可以在 Documentation 目录中查找有没有对应的文档。

5、drivers 目录

驱动目录文件,此目录根据驱动类型的不同,分门别类进行整理,比如 drivers/i2c 就是 I2C相关驱动目录,drivers/gpio 就是 GPIO 相关的驱动目录,这是我们学习的重点。

6、firmware 目录

此目录用于存放固件。

7、fs 目录

此目录存放文件系统,比如 fs/ext2、fs/ext4、fs/f2fs 等,分别是 ext2、ext4 和 f2fs 等文件系统。

8、include 目录

头文件目录。

9、init 目录

此目录存放 Linux 内核启动的时候初始化代码。

10、ipc 目录

IPC 为进程间通信,ipc 目录是进程间通信的具体实现代码。

11、kernel 目录

Linux 内核代码。

12、lib 目录

lib 是库的意思,lib 目录都是一些公用的库函。

13、mm 目录

此目录存放内存管理相关代码。

14、net 目录

此目录存放网络相关代码。

15、samples 目录

此目录存放一些示例代码文件。

16、scripts 目录

脚本目录,Linux 编译的时候会用到很多脚本文件,这些脚本文件就保存在此目录中。

17、security 目录

此目录存放安全相关的文件。

18、sound 目录

此目录存放音频相关驱动文件,音频驱动文件并没有存放到 drivers 目录中,而是单独的目录。

19、tools 目录

此目录存放一些编译的时候使用到的工具。

20、usr 目录

此目录存放与 initramfs 有关的代码。

21、virt 目录

此目录存放虚拟机相关文件。

22、.config 文件

跟 uboot 一样,.config 保存着 Linux 最终的配置信息,编译 Linux 的时候会读取此文件中的配置信息。最终根据配置信息来选择编译 Linux 哪些模块,哪些功能。

23、Kbuild 文件

有些 Makefile 会读取此文件。

24、Kconfig 文件

图形化配置界面的配置文件。

25、Makefile 文件

Linux 顶层 Makefile 文件,建议好好阅读一下此文件。

26、README 文件

此文件详细讲解了如何编译 Linux 源码,以及 Linux 源码的目录信息,建议仔细阅读一下此文件。

关于 Linux 源码目录就分析到这里,接下来分析一下 Linux 的顶层 Makefile。

顶层 Makefile 详解

具体参考正点原子手册,此处暂略。

make zImage 过程

vmlinux、Image,zImage、uImage 的区别

前面几小节重点是讲 vmlinux 是如何编译出来的,vmlinux 是 ELF 格式的文件,但是在实际中我们不会使用 vmlinux,而是使用 zImage 或 uImage 这样的 Linux 内核镜像文件。那么vmlinux、zImage、uImage 他们之间有什么区别呢?

①、vmlinux 是编译出来的最原始的内核文件,是未压缩的,比如正点原子提供的 Linux 源码编译出来的 vmlinux 差不多有 16MB,如图 35.5.5.1 所示:

②、Image 是 Linux 内核镜像文件,但是 Image 仅包含可执行的二进制数据。Image 就是使用 objcopy 取消掉 vmlinux 中的一些其他信息,比如符号表什么的。但是 Image 是没有压缩过的,Image 保存在 arch/arm/boot 目录下,其大小大概在 12MB 左右如图 35.5.5.2 所示:

相比 vmlinux 的 16MB,Image 缩小到了 12MB。

③、zImage 是经过 gzip 压缩后的 Image,经过压缩以后其大小大概在 6MB 左右,如图35.5.5.3 所示:

④、uImage 是老版本 uboot 专用的镜像文件,uImag 是在 zImage 前面加了一个长度为 64字节的"头",这个头信息描述了该镜像文件的类型、加载位置、生成时间、大小等信息。但是新的 uboot 已经支持了 zImage 启动!所以已经很少用到 uImage 了,除非你用的很古老的 uboot。

使用"make"、"make all"、"make zImage"这些命令就可以编译出 zImage 镜像,在arch/arm/Makefile 中有如下代码:

示例代码 35.5.5.1 顶层 Makefile 代码段
310 BOOT_TARGETS = zImage Image xipImage bootpImage uImage
......
315 $(BOOT_TARGETS): vmlinux
316 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

第 310 行,变量 BOOT_TARGETS 包含 zImage,Image,xipImage 等镜像文件。

第 315 行,BOOT_TARGETS 依赖 vmlinux,因此如果使用"make zImage"编译的 Linux 内核的话,首先肯定要先编译出 vmlinux。

第 316 行,具体的命令,比如要编译 zImage,那么命令展开以后如下所示:

@ make -f ./scripts/Makefile.build obj=arch/arm/boot MACHINE=arch/arm/boot/zImage

看来又是使用 scripts/Makefile.build 文件来完成 vmlinux 到 zImage 的转换。

关于 Linux 顶层 Makefile 就讲解到这里,基本和 uboot 的顶层 Makefile 一样,重点在于vmlinux 的生成。最后将 vmlinux 压缩成我们最常用的 zImage 或 uImage 等文件。

相关推荐
Ceder1c1 分钟前
【已解决】Linux ubuntu 20.04 docker 不需要sudo权限
linux·ubuntu·docker
GuokLiu4 分钟前
240912-设置WSL中的Ollama可在局域网访问
linux·api·wsl·ollama
池央17 分钟前
【Linux】常用指令详解一(ls,-a,-l,-d,cd,pwd,mkdir,touch,rm,clear)
linux·服务器
Tom哈哈26 分钟前
Ubuntu NFS 搭建及配置
linux·服务器·ubuntu
明明如月学长1 小时前
软考高级:逻辑地址和物理地址转换 AI解读
linux
Pres1X1 小时前
hackmyvm靶场--zon
linux
Aiden_SHU1 小时前
ftrace - 几种tracer的打印例子
linux·ftrace·latency
MonkeyKing_sunyuhua1 小时前
Ubuntu 24.04 上安装 Conda
linux·ubuntu·conda
SG.xf2 小时前
ftp服务的管理及安全优化
linux·服务器·网络
latesummer_2 小时前
Linux下rpm方式部署mysql(国产化生产环境无联网服务器部署实操)
linux·运维·服务器