目录
1 Linux简介
1.1 Linux的内核版本
1.2 Linux的发展历史
1.3 Linux的发行版本
1.4 Linux内核源码目录结构
2 Linux内核的配置和编译
2.1 Linux的配置
2.2 Linux内核的编译
2.2.1 Linux的Makefile体系
2.2.2 Linux内核文件编译
2.2.3 Makefile如何决定编译哪些文件
2.3.4 Makefile是怎样编译这些文件的?
2.3.5 Makefile是怎样连接这些文件
2.3.6 Makefile分析的总结
3 Linux内核的Kconfig分析
3.1 config
3.3 choice
3.4 comment
3.5 source
5.编译Linux内核
Linux主要作为Linux发行版(通常被称为"distro")的一部分而使用。这些发行版由个人、松散组织的团队、商业机构和志愿者组织编写。它们通常包括了其他的系统软件和应用软件,以及一个用来简化系统初始安装的安装工具,和让软件安装升级的集成管理器。
发行版为许多不同的目的而制作,包括对不同计算机结构的支持,对一个具体区域或语言的本地化,实时应用,和嵌入式系统,甚至许多版本故意地只加入免费软件。
目前,超过三百个发行版被积极的开发,最普遍被使用的发行版有大约十二个。
一个典型的Linux发行版包括:Linux内核,一些GNU程序库和工具,命令行shell,图形界面的X Window系统和相应的桌面环境,如KDE或GNOME,并包含数千种从办公套件,编译器,文本编辑器到科学工具的应用软件。
目前最著名的发行版有Debian,红帽(RedHat)、Ubuntu、Suse、CentOS、Fedora等。
国内比较著名的linux版本:红旗Linux,深度。
内核提供了多种不同的工具来简化内核的配置:
make config最简单的一种是字符界面下命令行工具。这个工具会依次遍历内核所有的配置项,要求用户进行逐项的选择配置。这个工具会耗费用户太多时间,除非万不得以(你的编译主机不支持其他配置工具)一般不建议使用。
make menuconfig。基于文本的,利用ncurse库编制的图形界面工具,键盘操作。相信以前对2.4内核比较熟悉的用户一定不会陌生。make menuconfig的界面
make xconfig。在2.6内核中提供了更漂亮和方便的基于X11的图形配置工具,就是说你要在KDE、GNOME之类的X桌面环境下才可用,支持鼠标。当用户使用这个工具对Linux内核进行配置时,界面下方会出现这个配置项相关的帮助信息和简单描述。make xconfig的界面如下:
make oldconfig。但是当你修改过配置文件之后,可以使用这个命令来验证和更新配置。
当用户完成配置后,配置工具会自动生成.config文件,它被保存在内核代码树的根目录下。用户可以很容易找到它,当然用户也可以直接对这个文件进行简单的修改。
Linux内核要编译哪些文件,怎样编译这些文件以及怎样连接这些文件,这都是通过Makefile来实现。
Makefile是根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成Linux内核二进制文件。 当一切工作完成以后,用户只需要简单键入make,剩下所有的工作Makefile就会自动替你完成了。
从Linux内核2.6开始,Linux内核的编译采用Kbuild系统,这同过去的编译系统有很大的不同,尤其对于Linux内核模块的编译。Linux的Makefile体系由如下几部分组成:
Kbuild Makefile的文件名不一定是Makefile,尽管推荐使用Makefile这个名字。大多的Kbuild文件的名字都是Makefile。为了与其他Makefile文件相区别,你也可以指定Kbuild Makefile的名字为Kbuild。而且如果“Makefile”和“Kbuild”文件同时存在,则Kbuild系统会使用“Kbuild”文件。
Kbuild Makefile的一个最主要功能就是指定编译什么,这个功能是通过obj-?、lib-y和目录递归来实现的。
obj-?。其中的“?”可能是“y”或“m”,“y”指定把对象编译进内核中,“m”指定把对象编译为模块。语法如下:obj-? = $(target).o。target为编译对象的名字。如果没有指定xxx-objs,这编译这个对象需要的源文件就是$(target).c或$(target).s。如果指定了$(target)-objs,则编译这个对象需要的源文件由$(target)-objs指定,并且不能有$(target).c或$(target).s文件。xxx-objs指定了编译对象需要的文件,一般只有在源文件是多个时才需要它。
#drivers/isdn/i4l/Makefile
obj-$(CONFIG_ISDN) += isdn.o
isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
#drivers/isdn/i4l/Makefile
# Makefile for the kernel ISDN subsystem and device drivers.
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
lib-y。列出的objects由当前目录下的.c或.S文件编译生成,在那个文件夹中被综合进单独的一个库,即lib.a。列在obj-y和附加列在lib-y中的objects将不会被包含在库中,也就是说同时出现在obj-y和lib-y的objects不会被包含进lib.a中。值得注意的是kbuild makefile可能列出文件用作 built-in,并且作为库的一部分。因此,同一个文件夹可能包含一个 built-in.o和lib.a文件。
Example:
#arch/i386/lib/Makefile
lib-y := checksum.o delay.o
这个例子创建一个基于checksum.o和delay.o的库文件。lib-y的使用方法通常被限制在lib/和arc/*/lib中。
目录递归。一个Makefile只负责在它自己的文件夹中构建objects。在子文件夹中的文件应该由子文件夹中的Makefiles来编译,系统将会自动递归地用在子文件夹中的Makefiles, 在这种情况下obj-y和obj-m就被使用了。
Example:
#fs/Makefile
obj-$(CONFIG_EXT2_FS) += ext2/
如果CONFIG_EXT2_FS被设置成y(built-in)或者m(modular),相应的obj-变量将会被设置,并且kbuild将会从ext2文件夹继承下来。Kbuild只会使用这些信息来决定它需要访问这些文件夹,而在子文件夹中的Makefile来指明哪些是modules哪些是built-in。
(1)顶层Makefile决定内核根目录下哪些子目录将被编进内核;
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文件将Linux源码的子目录分成了init-y、drivers-y、net-y、lib-y和core-y。并直接包含arch/$(ARCH)/Makefle文件:
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
SRCARCH := $(ARCH)
...
include $(srctree)/arch/$(SRCARCH)/Makefile
(2)arch/$(ARCH)/Makefile决定arch/$(ARCH)目录下哪些文件、哪些目录将被编进内核;
以ARM体系为例:
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
textofs-y := 0x00008000
...
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += $(machdirs) $(platdirs)
core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
core-$(CONFIG_VFP) += arch/arm/vfp/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
libs-y := arch/arm/lib/ $(libs-y)
head-y直接用文件名表示,对于没有MMU的处理器,MMUEXT的值为 -nommu,对应的文件为head-nommu.S;对于有MMU的处理器,MMUEXT的值为空,对应的文件为head.S。
在编译内核时,将依次进入init-y、core-y、libs-y、drvers-y、和net-y所指出的目录中执行该目录下的Makefile,每个子目录都会生成一个buld-in.o文件,libs-y所指定的目录下有可能生成lib.a文件。最后,head-y所指定的文件和build-in.o、lib.a文件一起被连接成映像文件vmlinux。
(3)各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件将被编成模块(即驱动程序),进入那些子目录继续调用它们的Makefile。
在include/config/auto.conf文件中,变量的值主要有两类:“y ”和“m”。各级子目录的Makefile使用这些变量来决定哪些文件被编进内核中,哪些文件被编成模块(即驱动程序), 要进入那些下一级子目录继续编译。
即编译选项、连接选项是什么
选项分3类:
在顶层的Makefile和arch/$(ARCH)/Makefle中定义了:head-y、init-y、drivers-y、net-y、lib-y和core-y(除head-y外,其他的都是目录名)。在顶层Makefle中,这些目录名的后面直接加buld-in.o或者lib.a,表示连接到内核中:
init-y := $(patsubst %/, %/built-in.o, $(init-y))
core-y := $(patsubst %/, %/built-in.o, $(core-y))
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
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)
注:字符串处理函数patsubst的用法:$(patsubst pattern,replacement,text)寻找“text”中符合格式“pattern”的字符,用“replacement”替换。比如init-y的初始值为init/,经过处理后,“init-y”变为“init/built-n.o”。
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/$(SRCARCH)/kernel/vmlinux.lds
目标文件的连接顺序为: head-y、init-y、core-y、lib-y、drivers-y和net-y。
对于ARM体系,Linux的连接脚本为arch/arm/kernel/vmlinux.lds.S文件。
Kconfig的基本要素包括:
config条目用来配置一个选项,它用于生成一个变量,这个变量会连同它的值一起被写入配置文件.config中。 config出现的三种配置结果:
CONFIG_LEDS_S3C24XX=y #对应的文件被编进内核
CONFIG_LEDS_S3C24XX=m #对应的文件被编成模块
#CONFIG_LEDS_S3C24XX #对应的文件没有被使用
下面举一个例子来说明config的格式,代码选自drivers/char中,用于配置CYCLADES:
config CYCLADES
tristate "Cyclades async mux support"
depends on SERIAL_NONSTANDARD && (PCI || ISA)
select FW_LOADER
---help---
This driver supports Cyclades Z and Y multiserial boards.
You would need something like this to connect more than two modems to
your Linux box, for instance in order to become a dial-in server.
For information about the Cyclades-Z card, read
.
To compile this driver as a module, choose M here: the
module will be called cyclades.
If you haven't heard about it, it's safe to say N.
menu条目用于生成菜单,格式如下:
“menu”
menu之后出现的字符串是菜单名,“menu”和“endmenu”之间有很多config。
#
# Video configuration
#
menu "Graphics support"
depends on HAS_IOMEM
source "drivers/char/agp/Kconfig"
source "drivers/gpu/drm/Kconfig"
config VGASTATE
tristate
default n
config VIDEO_OUTPUT_CONTROL
tristate "Lowlevel video output switch controls"
...
endmenu
choice条目将多个类似的配置选项组合在一起,供用户单选或多选,格式如下:
“choice”
“endchoice”
实际使用中,会在“choice”和“endchoice”中定义多个config。
menu "System Type"
choice
prompt "ARM system type"
default ARCH_VERSATILE
...
config ARCH_SA1100
bool "SA1100-based"
...
config ARCH_S3C2410
bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
...
config ARCH_S3C64XX
bool "Samsung S3C64XX"
...
endchoice
...
endmenu
if ARCH_S3C2410
source "arch/arm/mach-s3c2400/Kconfig"
source "arch/arm/mach-s3c2410/Kconfig"
source "arch/arm/mach-s3c2412/Kconfig"
source "arch/arm/mach-s3c2440/Kconfig"
source "arch/arm/mach-s3c2442/Kconfig"
source "arch/arm/mach-s3c2443/Kconfig"
endif
comment条目用于定义一些帮助信息,它在配置过程中出现在界面的第一行.并且这些 帮助信息会出现在配置文件中(作为注释),格式如下:
“comment”
例子,选自arch/arm/Kconfig
menu “Floating point emulation”
comment “At least one emulation must be selected”
source条目用于读入另一个Kconfig文件, 格式如下:
“source”
下面是一个例子,代码选自drivers目录下:
source "drivers/base/Kconfig"
source "drivers/connector/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/of/Kconfig"
Step1: 拷贝arch/arm/configs/s3c2410_defconfig为文件.config #cp arch/arm/configs/s3c2410_defconfig .config
Step2: 修改内核目录下的Makefile
CROSS_COMPILE ?= arm-linux-
ARM ?= arm
Step3: 执行make menuconfig,并保存,如果有问题,以root权限执行 #make menuconfig
Step4: 编译内核 #make zImage 编译完成后,zImage放在/arch/arm/boot/zImage。