目的:
分析Makefile在内核中的作用
Makefile的作用总结:
1)决定编译哪些文件?
2)怎样编译这些文件?
3)怎样连接这些文件,最重要的是他们的顺序如何?
1、linux内核中Makefile体系
顶层Makefile |
所以Makefile的核心,根据不同平台,对各类target分类并调用相应的规则Makefile生成目标 |
.config |
配置文件,配置内核是生成。所有Makefile都是根据 .config 来决定使用哪些文件 |
arch/$(ARCH)/Makefile |
具体平台相关的Makefile,相关决定哪些体系结构相关的文件参与内核的生成 |
scripts/Makefile.* |
通用规则文件,面向所有的Kbuild Makefiles |
各子目录下的Makefile 文件 |
由其上层目录的Makefile调用,执行其上层传递下来的命令 |
根据Makefile的3大作用分析这5类文件。
(1)决定编译哪些文件
linux内核的编译是从顶层的Makefile开始的,然后递归地进入各级子目录调用各自的Makefile,分为3个步骤:
a、顶层Makefile决定内核目录下哪些子目录将被编进内核
b、arch/$(ARCH)/Makefile 决定所在目录下哪些文件、目录编入内核
c、各级子目录下的Makefile决定所在目录下哪些文件编入内核,哪些文件编成模块(即驱动程序),进入哪些子目录继续调用他们的Makefile。
先看步骤A,在顶层Makefile可看到:
# Objects we will link into vmlinux / subdirs we need to visit init-y := init/ drivers-y := drivers/ sound/ net-y := net/ libs-y := lib/ core-y := usr/
......
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
可知,顶层Makefile将内核下的目录分为5类,
init-y : drivers-y : net-y : libs-y :core-y
(arch目录会在arch/$(ARCH)/Makefile 中被包含入内核)
可以在顶层目录的Makefile修改ARCH变量,如下
//修改前 ARCH ?= $(SUBARCH) ARCH ?= ? //修改后 ARCH ?= arm CROSS_COMPILE ?= arm-linux-
对于步骤B的arch/$(ARCH)/Makefile,以ARM体系为例,在arch/arm/Makefile中可看到:
...... core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += $(MACHINE) ... core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2440/ core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2442/ ... core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) core-$(CONFIG_VFP) += arch/arm/vfp/ ......
可以看到Makefile对core-y的内容进行了进一步的扩展,在这个Makefile中,出现了另一类:head-y,不过它是直接以文件名出现的。
#Default value
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
编译内核时,将依次进入init-y : drivers-y : net-y : libs-y :core-y 所列出的目录中执行各自的Makefile,每个子目录都会生成一个build-in.o ,最后head-y所表示的文件将和这些build-in.o一起连接成内核印象文件 vmlinux。
最后,看看步骤C怎么进行的:
步骤3的作用:“各级子目录下的Makefile决定所在目录下哪些文件编入内核,哪些文件编成模块(即驱动程序),进入哪些子目录继续调用他们的Makefile“”。
在配置内核时,会生成.config ,在顶层Makefile中会有以下语句间接包含.config文件,以后就根据.config中定义的各变量决定编译时用哪些文件(实际包含的是与.config等效的auto,conf)
# Read in config -include include/config/auto.conf
auto.conf内容如下:
# Automatically generated make config: don't edit # Linux kernel version: 2.6.22.6 # Wed Feb 19 07:48:42 2020 CONFIG_CPU_S3C244X=y CONFIG_CPU_COPY_V4WB=y CONFIG_DEBUG_USER=y CONFIG_FLATMEM=y ...
这些变量的值主要有两类,"y" , "m"。各级子目录的Makefile使用这些变量决定哪些文件编进内核,哪些文件编成模块,要进入哪些子目录继续决定编译。具体通过以下方法确定:
1)obj-y 用来决定哪些文件编进内核
2)obj-m 用来定义哪些文件编成可加载模块
3)lib-y 用来定义哪些文件编成库文件
4)obj-y , obj-m 还可以用来指定要进入的下一层目录
(2)怎样编译这些文件。
即编译选项、连接选项是什么。这些选项分为3类:全局的(适用于整个南海代码树);局部的(仅适用某个Makefile中的文件);个体的(仅适用某个文件)
全局选项在顶层Makefile和arch/$(ARCH)/Makefile 中定义,局部选项在各个子目录的Makefile中。
(3) 怎样连接这些文件,它们的顺序如何
在前面分析哪些文件会编进内核时,知道顶层Makefile和 arch/$(ARCH)/Makefile 定义了6类目录(或文件):
head-y , init-y , drivers-y , net-y , libs-y , core-y 。以ARM体系为例,它们的初始值如下:
在arch/arm/Makefile 中:
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += $(MACHINE) ... core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2440/ core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2442/ ... libs-y := arch/arm/lib/ $(libs-y)
在顶层Makefile中:
443 - 556行
init-y := init/ drivers-y := drivers/ sound/ net-y := net/ libs-y := lib/ core-y := usr/ ...... core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
可见,除了head-y之外,其余的init-y , drivers-y等都是目录名。在顶层Makefile中,这些目录名的后面直接加上build-in.o 或 lib.a ,表示要链接进内核的文件,如下所示:
567 - 573行 等价于箭头后的表达 init-y := $(patsubst %/, %/built-in.o, $(init-y)) ---> init/build-in.o core-y := $(patsubst %/, %/built-in.o, $(core-y)) ---> core/build-in.o drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))--> drievrs/build-in.o net-y := $(patsubst %/, %/built-in.o, $(net-y)) libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) libs-y := $(libs-y1) $(libs-y2)
在顶层Makefile中,再往下看:
602 - 605 行
vmlinux-init := $(head-y) $(init-y) vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) vmlinux-all := $(vmlinux-init) $(vmlinux-main) vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds export KBUILD_VMLINUX_OBJS := $(vmlinux-all)
vmlinux-all 表示所有构成内核印象文件vmlinux的目标文件,带入后等价于以下:
vmlinux-all := $(head-y) $(init-y) $(core-y) $(libs-y) $(drivers-y) $(net-y)
已知上面的这些文件init-y等会生成对应的文件init/build-in.o文件被编译进内核。
vmlinux-lds表示连接脚本。顶层Makefile会按照一定的顺序组织文件,根据此链接脚本生成内核映像文件。
vmlinux # ^ # | # +-< $(vmlinux-init) # | +--< init/version.o + more # | # +--< $(vmlinux-main) # | +--< driver/built-in.o mm/built-in.o + more # | # +-< kallsyms.o (see description in CONFIG_KALLSYMS section)
参考:
《linux应用开发完全手册》 --韦东山
https://www.cnblogs.com/lifexy/p/7348534.html