1.配置交叉编译器
默认情况下,内核构建的是与宿主机相同的体系架构镜像。如果要交叉编译,需要设置两个变量ARCH和CORSS_COMPILE。
①ARCH:指明目标体系架构,如x86、arm、mips等。
②CROSS_COMPILE:指定使用的交叉编译器的前缀。例如arm-linux-。在内核顶层的Makefile中,可以看到工具链中的编译器、链接器等都是以$(CROSS_COMPILE)作为前缀。
AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld REAL_CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump
我们可以在每次执行make时,通过下面的命令来给这两个变量赋值
make ARCH=arm CROSS_COMPILE=arm-linux-
或者直接修改顶层Makefile,将
ARCH ?= $ (SUBARCH)
CROSS_COMPILE ?=
修改为
ARCH ?= arm
CROSS_COMPILE ?= arn-linux-
2.加载默认配置
在内核源码 arch/
make ARCH=arm CROSS_COMPILE=arm-linux- xxx_defconfig
这个操作等同于将arch/arm/configs/目录下的xxx_defconfig文件复制为.config
我们可以使用命令
make help
来获取帮助
3.配置内核
我们可使用命令
make menuconfig
来以菜单的形式配置内核。
4.生成内核
我们可以通过下面命令编译内核
make zImage
可以通过下面的命令编译内核模块
make modules
编译生成的内核镜像位于内核源码/arch/arm/boot目录和arch/arm/boot/compressed目录下。
①vmlinux.o是链接后生成的内核的目标文件
②vmlinux(根目录)是ELF格式的内核
③System.map是内核的富豪榜
④Image是二进制的内核文件,由vmlinux转换而成
⑤vmlinux(compressed目录)是经压缩的vmlinux镜像(通过gzip算法压缩)和解压缩程序的组合体,也是ELF格式
⑥zImage是解压缩程序和内核的组合
5.内核构建系统
名称 | 描述 |
顶层Makefile | 他是所有Makefile文件的核心,从总体上控制内核的编译和链接 |
.config | 配置文件,在配置内核时产生。所有Makefile文件(包括顶层目录及各级子目录)都是根据.config来决定使用哪些文件 |
arch/$(ARCH)/Makefile | 对应体系结构的Makefile,它用来决定哪些体系结构相关的文件参与内核的生成,并提供一些规则来生成特定格式的内核映像。 |
scripts/makefile.* | Makefile公用的通用规则、脚本等 |
kbuild Makefiles | 各级子目录下的Makefile,他们相对简单,被上一层Makefile调用来编译当前目录下的文件 |
Makefile:分布在内核源代码中的Makefile,定义内核的编译规则,配合Kconfig使用
Kconfig:配置文件,给用户提供配置选项的功能,make menuconfig 等命令根据此文件生成配置菜单
配置工具:包括配置命令解析器(解析Kconfig)和内核配置用户界面程序等
5.1 内核Kconfig
在执行make zImage来构建内核镜像之前,我们通常会响拷贝一个默认的xxx_defconfig来替换掉.config,或者运行 make xxx_defconfig以此来获得一个默认的内核配置文件,然后再运行make menuconfig 等来进一步定制内核。
make menuconfig等配置工具是通过读取arch/
内核源码每个子目录中,都有一个Makefile文件和Kconfig文件。Makefile用来配置目标文件的生成过程。Kconfig用于配置内核,它就是各种配置界面的源文件。内核的配置工具读取各个Kconfig文件,生成配置界面供开发人员配置内核,最后生成配置文件.config。
内核的配置界面以树状的菜单形式组织,主菜单下有若干子菜单,子菜单下又有子菜单或配置选项。每个子菜单或选项都有依赖关系,这些依赖关系用来确定它们是否显示。只有被依赖的父项已经被选中,子项才会显示。下面看一下Kconfig的基本语法。
Kconfig语法比较丰富,按功能可分为配置选项描述语句和菜单结构描述语句。
①Kconfig 文件的基本要素:config关键字(entry)
config 条目常被其他条目包含,用来生成菜单,进行多项选择等。config 条目用来配置一个选项,或者这么说,它用于生成一个变量,这个变量会连同它的值一起被写入配置文件 .config 中。也就是说config关键字定义了新的配置选项,之后的几行定义了该配置选项的属性。配置选项的属性包括类型、数据范围、输入提示、依赖关系、帮助信息和默认值等。
比如有一个config 条目用来配置CONFIG_XXX,根据用户的选择,.config文件中可能出现下面3种配置结果中的一个。
CONFIG_XXX=y # 对应的文件被编进内核 CONFIG_XXX=m # 对应的文件被编成模块 #CONFIG_XXX # 对应的文件没有被使用
比如
config TINY4412_LEDS #配置选项的名称 tristate "LED Support for FriendlyARM Tiny4412 GPIO LEDs" #tristate是变量类型有5种 #Bool 布尔类型,结果是Y[*] , N[] #tristate 三项选择,结果是Y[*], N[], M[m] #String 字符串, 结果(arm-linux-) #Hex 十六进制 #Int 十进制 depends on MACH_TINY4412 #依赖 #当依赖满足事,当前配置选项的提示信息才会出现,才能设置当前配置选项 #如果依赖条件不满足,则它取默认值。 default y #默认为y help #帮助信息 This option enables support for LEDs connected to GPIO lines on Tiny4412 boards.
在通过make menuconfig来配置时的的效果如下
②menu关键字
menu条目用于生成菜单, 在menuconfig 中是以------>形式出现 格式如下:
“menu”
menu之后字符串是菜单名,“menu”和“endmunu”之间有很多config条目。在配置界面上回出现如下字样的菜单,移动光标选中它后按回车键进入,就会看到这些config条目定义的配置选项。
③Source关键字
在当前Kconfig包含其它目录下的kconfig,用于读入另一个Kconfig文件,格式如下:
“source”
下面看一个例子
menu "Device Drivers" #菜单开始 source "drivers/tty/Kconfig" #引入drivers/tty目录下的Kconfig ...... config TINY4412_LEDS tristate "LED Support for FriendlyARM Tiny4412 GPIO LEDs" depends on MACH_TINY4412 default y help This option enables support for LEDs connected to GPIO lines on Tiny4412 boards. ...... endmenu#菜单结束
④Choice关键字
choice条目将多个类似的配置选项组合在一起,供用户单选或多选,格式如下:
“choice”"end choice"
实际使用中,也是在“choice”和“endchoice”之间定义多个config条目。
同样也来看一个例子
choice prompt "Kernel compression mode" default KERNEL_GZIP depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO help The linux kernel is a kind of self-extracting executable. Several compression algorithms are available, which differ in efficiency, compression and decompression speed. Compression speed is only relevant when building a kernel. Decompression speed is relevant at each boot. If you have any problems with bzip2 or lzma compressed kernels, mail me (Alain Knaff). (An older version of this functionality (bzip2 only), for 2.4, was supplied by Christian Ludwig) High compression options are mostly useful for users, who are low on disk space (embedded systems), but for whom ram size matters less. If in doubt, select 'gzip' config KERNEL_GZIP bool "Gzip" depends on HAVE_KERNEL_GZIP help The old and tried gzip compression. It provides a good balance between compression ratio and decompression speed. config KERNEL_BZIP2 bool "Bzip2" depends on HAVE_KERNEL_BZIP2 help Its compression ratio and speed is intermediate. Decompression speed is slowest among the choices. The kernel size is about 10% smaller with bzip2, in comparison to gzip. Bzip2 uses a large amount of memory. For modern kernels you will need at least 8MB RAM or more for booting. config KERNEL_LZMA bool "LZMA" depends on HAVE_KERNEL_LZMA help This compression algorithm's ratio is best. Decompression speed is between gzip and bzip2. Compression is slowest. The kernel size is about 33% smaller with LZMA in comparison to gzip. config KERNEL_XZ bool "XZ" depends on HAVE_KERNEL_XZ help XZ uses the LZMA2 algorithm and instruction set specific BCJ filters which can improve compression ratio of executable code. The size of the kernel is about 30% smaller with XZ in comparison to gzip. On architectures for which there is a BCJ filter (i386, x86_64, ARM, IA-64, PowerPC, and SPARC), XZ will create a few percent smaller kernel than plain LZMA. The speed is about the same as with LZMA: The decompression speed of XZ is better than that of bzip2 but worse than gzip and LZO. Compression is slow. config KERNEL_LZO bool "LZO" depends on HAVE_KERNEL_LZO help Its compression ratio is the poorest among the choices. The kernel size is about 10% bigger than gzip; however its speed (both compression and decompression) is the fastest. endchoice
配置时的界面如下所示
5.2 内核中的Makefile
内核中的Makefile的作用主要有以下几点:
①决定编译哪些文件
②怎样编译这些文件
③怎样连接这些文件,最重要的是它们的顺序如何
(1)决定编译哪些文件
Linux内核的编译过程从顶层Makefile开始,然后递归地进入各级子目录调用他们的makefile,分为3个步骤:
①顶层Makefile 决定内核根目录下哪些子目录将被编进内核;
②arch/
③各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件将被编成模块(即驱动程序),进入哪些子目录继续调用它们的Makefile。
在顶层Makefile 中可以看到如下内容:
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ drivers-y := drivers/ sound/ firmware/ net-y := net/ libs-y := lib/ core-y := usr/
我们可以看到,最重要的arch目录没有出现在内核中。它在arch/$(ARCH)/Makefile中被包含进内核,在顶层Makefile中直接包含了这个Makefile
include $(srctree)/arch/$(SRCARCH)/Makefile
对于ARCH变量,可以在执行make时传入,比如make ARCH=arm 。另外,对于非X86平台,还需要指定交叉编译工具,这也可以在执行make 命令时传入,比如make CROSS_COPILE=arm-linux- 。
对于arch/
#对应arch/arm/kernel/head.o head-y := arch/arm/kernel/head$(MMUEXT).o ...... core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) core-$(CONFIG_VFP) += arch/arm/vfp/ # If we have a machine-specific directory, then include it in the build. core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += arch/arm/net/ core-y += $(machdirs) $(platdirs) drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ libs-y := arch/arm/lib/ $(libs-y)
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。
在各级子目录下的也有各自的Makefile它的主要作用和为:
在配置内核时,生成配置文件.config。内核顶层Makefile使用如下语句间接包含.config 文件,以后就根据.config中定义的各个变量决定编译哪些文件。它包含了include/config/auto.conf 文件,然后将.config文件中的注释去掉,并根据顶层Makefile中定义的变量增加一些变量。
#linux-3.5/drivers/char/Makefile obj-$(CONFIG_TINY4412_LEDS) += tiny4412_leds.o obj-$(CONFIG_TINY4412_HELLO_MODULE) += tiny4412_hello_module.o obj-$(CONFIG_TINY4412_BUTTONS) += tiny4412_buttons.o obj-$(CONFIG_TINY4412_BUZZER) += tiny4412_pwm.o obj-$(CONFIG_TINY4412_BACKLIGHT)+= tiny4412_backlight.o obj-$(CONFIG_TINY4412_ADC) += tiny4412_adc.o
链接方式:
对于ARM体系,连接脚本就是arch/arm/kernel/vmlinux.lds,它由 arch/arm/kernel/vmlinux/lds.S文件生成。
6.向内核中添加新模块
无论是向内核中添加新的功能还是驱动程序,都需要将相应的代码添加到内核构建系统中,需要完成以下三个工作:
①将编写的源码复制到Linux内核源码相应的目录下
②在目录的Kconfig文件中添加新源码对应项目的编译配置选项
③在目录Makefile文件中增加对新源码的编译条目
下面以刚才的Led驱动为例来说明
①将编写的源码复制到Linux内核源码相应的目录下
②在目录的Kconfig文件中添加新源码对应项目的编译配置选项
③在目录Makefile文件中增加对新源码的编译条目