. Documentation/kbuild/makefiles.txt
. Makefile的作用:
1). 决定编译哪些文件
2). 怎么编译这些文件
3). 怎么样链接这些文件(顺序)
. Makefile 类别:
//顶层Makefile
. Makefile the top Makefile.
//体系结构相关Makefile
. arch/$(ARCH)/Makefile the arch Makefile.
具体体系结构相关的哪些文件被编译。
并提供一些规则来生成对应体系结构的image.
//子目录Makefile
. kbuild Makefiles there are about 500 of these.
//配置文件
. .config the kernel configuration file.
//Makefile共用规则、脚本
. scripts/Makefile.* common rules etc. for all kbuild Makefiles.
. 根据Makefile的3个作用来分析上面这5类文件:
1. 决定编译哪些文件
==================
内核的编译过程从top Makefile开始,然后递归的调用各级子目录中的Makefile,
分为以下3步:
1). top Makfiel决定内核根目录下的哪些子目录被编译进内核.
2). arch/$(ARCH)/Makefile决定arch/$(ARCH)下的哪些文件和目录被编译进内核.
3). 子目录Makefile决定子目录中哪些文件和目录被编译进内核,或编译成模块,或进入下一级目录继续调用Makefile.
1). top Makefile:
-----------------
. 根下的13个子目录分为5类:
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/
. 除去include和2个和无源码的目录
. 还有一个arch目录,在include $(srctree)/arch/$(ARCH)/Makefile中包含。
2). arch/$(ARCH)/Makefile
-------------------------
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
e.g: arch/arm/Makefile
//新类别head-y, 以文件名出现,head指定的都被链接在最前面
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
. 说明:
head$(MMUEXT)
= head-nommu.S
or
= head.S
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += $(machdirs) $(platdirs)
. 说明:
$(machdirs) = mach-s3c2410 mach-s3c2440
$(platdirs) = plat-s3c24xx
libs-y := arch/arm/lib/ $(libs-y)
core-$(CONFIG_xxx)
CONFIG_xxx在.config配置中得到,
y - 编译进内核
m - 模块
. 内核编译时,会根据5类top Makefile中的xxx-y,进入对应的子目录,
在每个目录下生成built-in.o, libs-y所列目录会生成lib.a, 加上head-y指定的head.o将它们按照一定的
顺序(head在最前面)链接成一个内核image -- vmlinux.
3). 各级子Makefile
------------------
obj-y -> built-in.o
obj-m -> 模块.ko
. built-in.o 还是模块.ko由配置文件的宏定义决定
obj-$(CONFIG_TEST) += test.o
.config:
在配置内核后生成一个.config配置文件,内核的Makefile就是根据它里面定义的Makefile中需要的
宏变量来决定哪些文件编译,怎么编译,和对代码功能的控制。
.config是在top Makefile中被间接包含的,
top Makefile包含的是auto.conf, 而auto.conf就是由.config生成的。
include/config/auto.conf
. 顺序:
obj-$(CONFIG_A) += a.o
obj-$(CONFIG_B) += b.o
如果被编译进内核,CONFIG_A/B = y
那么a.o中module_init(a_init)定义的a_init被先调用.
. 多文件组成:
obj-$(CONFIG_TEST) += test.o
test-objs := 1.o 2.o 3.o
. 有下级子目录:
obj-$(CONFIG_TEST) += lee/
这样就会自动进入下级子目录lee下看它的Makefile
e.g:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test/
Makefile
-------------
obj-$(CONFIG_TEST) += lee/
-------------
lee/
1.o 2.o Makefile
--------------
obj-$(CONFIG_LEE) += lee.o
lee-objs := 1.o 2.o
--------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2. 怎么编译这些文件
===================
即编译选项的问题.
kernel编译选项有3类:
1) 全局的(适用于整个内核代码树)
2) 局部的(仅用于某个Makefile文件)
3) 个体的(仅适用于某个源代码文件.c)
. 1)全局:
在top Makefile和arch/arm/Makefile中被定义.
CFLAGS
AFLAGS
LDFLAGS
ARFLAGS
. 2)局部的:
各子目录中的Makefile中定义,
EXTRA_CFLAGS
...
. 3)个体的:
CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
在gcc -Dxxx
以上3各编译选项在scripts/Makefile.lib中一起使用。
3. 怎么样链接,顺序
==================
. 根据2个顶层Makefile(Makefle, arch/arm/Makefile)定义的6类
head-y, init-y, drivers-y, net-y, libs-y, core-y
在这2个Makefile中将这6类找到, 可见除head-y定义的是文件,
其他的都定义的为目录.
那么这些目录是如何链接的呢,换句话说如何将这些目录下的所有.o链接起来的?
就是将这些目录下的所有.o统一到built-in.o中去,然后链接e.g:drivers/built-in.o
就可以了。
. patsubst字符串处理函数
$(patsubst pattern, replacement, text)
在"text"字串中找到"pattern",然后用replacement来替换它。
e.g:
test-y := a/ b/
test-y := (patsubst %/, %/built-in.o, $(test-y))
--->
test-y := a/built-in.o b/built-in.o
. vmlinux-all & vmlinux-lds:
如果是arm架构的vmlinux, 链接脚本vmlinux-lds := arch/arm/kernel/vmlinux.lds
. 内核Makefile总结:
~~~~~~~~~ 哪些文件被编译 ~~~~~~~~~~~~~~~~
1. .config配置文件定义宏变量,Makefile根据它来决定哪些文件被编译进内核,哪些编译成模块,代码中的宏.
2. 顶层Makefile和arch/$(ARCH)/Makefile决定根目录下哪些文件和子目录参加编译.
3. 子目录Makefile根据.config的宏变量定义决定哪些文件和目录参与编译,如果编译是编译进内核还是模块。
还可以进入下一级子目录继续调用下一级子目录的Makefile。
.config的宏变量:
CONFIG_xxx = y
CONFIG_xxx = m
CONFIG_xxx = not set //不被编译
~~~~~~~~~ 怎么编译 ~~~~~~~~~~~~~~~~
4. Makefile中定义的全局,局部,个体的编译选项影响如何编译.
~~~~~~~~~ 顺序, 链接 ~~~~~~~~~~~~~~~~~~~~~
5. 顶层Makefile按照一定的顺序组织文件,最后用arch/arm/kernel/vmlinux.lds链接成vmlinux.