内核的编译同样是从Makefile 来分析:
一、内核源码结构
Linux内核文件数目近2万,出去其他架构CPU的相关文件,他们分别位于顶层目录下的17个子目录,各个目录功能独立,下面是常用目录:
arch:体系结构相关代码
ipc:进程调度相关代码
mm:内存管理
Documentation:帮助文档
net:网络协议
lib:库
scripts:编译相关脚本工具
tools:编译相关工具
drivers:设备驱动
fs:文件系统实现
对于ARM 架构的Exynos4412,其体系相关的代码在arch/arm/目录下,在后面进行的Linux移植时,开始的工作正式修改这个目录下的文件。
二、Linux Makefile分析
内核中的哪些文件将被编译?它们是怎样被编译的?它们连接时的顺序如何确定?那个文件在最前面?哪些文件或函数先执行?这些都是通过Makefile 来管理的。从最简单的角度来总结Makefile的作用,有以下3点:
1)-- 决定编译哪些文件;
2)-- 怎样编译这些文件?
3)-- 怎样连接这些文件,最重要的是它们的顺序如何?
Linux 内核源码中含有很多个Makefile文件,这些Makefile文件又要包含其他一些文件(比如配置信息、通用的规则等)。这些文件构成了 Linux 的Makefile 体系,可以分为下表中的5类:
名称 | 描述 |
顶层Makefile | 他是所有Makefile文件的核心,从总体上控制内核的编译和链接 |
.config | 配置文件,在配置内核时产生。所有Makefile文件(包括顶层目录及各级子目录)都是根据.config来决定使用哪些文件 |
arch/$(ARCH)/Makefile | 对应体系结构的Makefile,它用来决定哪些体系结构相关的文件参与内核的生成,并提供一些规则来生成特定格式的内核映像。 |
scripts/makefile.* | Makefile公用的通用规则、脚本等 |
kbuild Makefiles | 各级子目录下的Makefile,他们相对简单,被上一层Makefile调用来编译当前目录下的文件 |
以下根据见面总结的Makefile 的3大作用分析这5类文件。
1、决定编译哪些文件
Linux内核的编译过程从顶层Makefile开始,然后递归地进入各级子目录调用他们的makefile,分为3个步骤:
a -- 顶层Makefile 决定内核根目录下哪些子目录将被编进内核;
b -- arch/$(ARCH)/Makefile 决定arch/$(ARCH)目录下哪些文件、哪些目录将被编进内核;
c -- 各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件将被编程模块(即驱动程序),进入哪些子目录继续调用它们的Makefile。
a -- 先看步骤a, 顶层Makefile的编译
在顶层Makefile 中可以看到如下内容:
可见,顶层Makefile将这14个子目录分为5类:init-y、divers-y、net-y、libs-y和core-y。
我们可以看到,最重要的arch目录没有出现在内核中。它在arch/$(ARCH)/Makefile中被包含进内核,在顶层Makefile中直接包含了这个Makefile,如下所示:
对于ARCH变量,可以在执行make时传入,比如“make ARCH=arm ...”。另外,对于非X86平台,还需要指定交叉编译工具,这也可以在执行make 命令时传入,比如“make CROSS_COPILE=arm-linux- ..”。为了方便,常在顶层Makefile中进行如下修改。这样执行make时就会将ARCH变量传入
b -- 看步骤 b,arch/$(ARCH)/Makefile的编译
对于步骤 b 的 arch/$(ARCH)/Makefile,以ARM为例,在arch/arm/Makefile 中可以看到如下内容:
从129行可知,除了刚面的5类子目录外,又出现了一类:head-y,不过它直接以文件名出现;
arch/arm/Makefile 中类似第268-273行的代码进一步扩展了core-y的内容,第276行扩展了libs-y的内容,这些都是体系相关的目录;第261-265行中的CONFIG_在配置内核时定义,它的值有3种:y、m或空。y表示编进内核,m表示编为模块,空表示不使用;
编译内核时,将依次进入init-y、core-y、libs-y、drivers-y和net-y 所列出的目录中执行它们的Makefile,每个子目录都会生成一个 built-in.o(libs-y所列目录下,有可能生成lib.a文件)。最后,head-y所表示的文件将和在这些built-in.o、lib.a 一起被连接成内核映像文件 vmlinux。
c -- 步骤 c 是如何进行的,各级子目录下的Makefile的编译
在配置内核时,生成配置文件.config。内核顶层Makefile使用如下语句间接包含.config 文件,以后就根据.config中定义的各个变量决定编译哪些文件。值所以说是“间接”包含,试音为包含的是include/config/auto.conf 文件,而它只是将.config文件中的注释去掉,并根据顶层Makefile中定义的变量增加一些变量而已。
2、怎样编译这些文件
即编译选项、连接选项是什么。这些选项分3类:全局的,适用于整个内核代码树;局部的,仅适用于某个Makefile中的所有文件;个体的,仅适用于某个文件。
全局选项在顶层Makefile和arch/$(ARCH)/Makefile 中定义,这些选项的名称为:CFLAGS、AFLAGS、LDFLAGS、ARFLAGS,他们分别是编译C文件的选项、编译汇编问价你的选项、连接文件的选项、制作库文件的选项。
3、怎样连接这些文件,它们顺序如何
前面分析有哪些文件要编进内核时,顶层Makefile和arch/$(ARCH)/Makefile定义了6类目录(或文件):head-y、init-y、drivers、libs-y 和 core-y。它们的初始值如下(以ARM体系为例)
arch/arm/Makefile 中:
顶层makefile 中:
可见,除head-y 外,其余的init-y、drivers-y等都是目录名。在顶层Makefile 中,这IE目录名的后面直接加上built-in.o 或 lib.a,表示要连接进内核的文件。
上面的patubst是个字符串处理函数,它的用法如下:
(patsubst pattern, replacement,text)
表示寻找“text”中符合格式“pattern”的字,用”replacement"替换它们。比如上面的init-y初值为“init/”,经过793行的交互后,“init-y” 变为“init/built - in.o”。
顶层Makefile中,再往下看:
对于ARM体系,连接脚本就是arch/arm/kernel/vmlinux.lds,它由 arch/arm/kernel/vmlinux/lds.S文件生成,先将生成的arch/arm/kernel/vmlinux.lds摘录如下:
总结:
a -- 配置文件.config 中定义了一系列的变量,Makefile将结合它们来决定哪些文件被编进内核、哪些文件被编进模块、涉及哪些子目录;
b -- 顶层Makefile和arch/$(ARCH)/Makefile决定根目录下哪些子目录、arch/$(ARCH) 目录下哪些文件和目录将被编进内核;
c -- 最后,各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件将被变成模块(即驱动程序),进入哪些子目录继续调用它们的Makefile;
d -- 顶层Nakedfile和arch/$(ARCH)/Makefile设置了可以影响所有文件的编译、连接选项:CFLAGS、AFLAGS、LDFLAGS、ARFLAGS;
e -- 顶层Makefile按照一定的顺序组织文件,根据连接脚本 arch/$(ARCH)/kernel/vmlinux.lds生成内核映像文件vmlinux。