Linux系统的Makefile、Kconfig和模块1Makefile1.1Makefile组织层次Linux的Make体系由如下几部分组成:Ø顶层Makefile顶层Makefile通过读取配置文件,递归编译内核代码树的相关目录,从而产生两个重要的目标文件:vmlinux和模块。
Ø内核相关Makefile位于arch/$(ARCH) 目录下,为顶层Makefile提供与具体硬件体系结构相关的信息。
Ø公共编译规则定义文件。
包括Makefile.build 、Makefile.clean、Makefile.lib、Makefile.host等文件组成。
这些文件位于scripts目录中,定义了编译需要的公共的规则和定义。
Ø内核配置文件 .config通过调用make menuconfig或者make xconfig命令,用户可以选择需要的配置来生成期望的目标文件。
Ø其他Makefile主要为整个Makefile体系提供各自模块的目标文件定义,上层Makefile根据它所定义的目标来完成各自模块的编译。
1.2Makefile的使用在编译内核之前,用户必须首先完成必要的配置。
Linux内核提供了数不胜数的功能,支持众多的硬件体系结构,这就需要用户对将要生成的内核进行裁减。
内核提供了多种不同的工具来简化内核的配置。
make config,字符界面下命令行工具,这个工具会依次遍历内核所有的配置项,要求用户进行逐项的选择配置。
这个工具会耗费用户太多时间,除非万不得以(你的编译主机不支持其他配置工具)一般不建议使用。
make menuconfig,基于ncurse库编制的图形界面工具,一般台式机使用该工具。
make xconfig,基于X11的图形配置工具,一般用于工作站环境。
当用户完成配置后,配置工具会自动生成.config文件,它被保存在内核代码树的根目录下。
当一切工作完成以后,用户只需要简单键入make或make zImage,剩下所有的工作makefile就会自动替你完成了。
1.3Makefile编译流程当用户使用Linux的Makefile编译内核版本时,Makefile的编译流程如下:Ø使用命令行或者图形界面配置工具,对内核进行裁减,生成.config配置文件Ø保存内核版本信息到include/linux/version.hØ产生符号链接include/asm,指向实际目录include/asm-$(ARCH)Ø为最终目标文件的生成进行必要的准备工作Ø递归进入/init 、/kernel、/drivers、/net、/lib等目录和其中的子目录来编译生成所有的目标文件Ø链接上述过程产生的目标文件生成vmlinux,vmlinux存放在内核代码树的根目录下Ø最后根据arch/$(ARCH)/Makefile文件定义的后期编译的处理规则建立最终的映象bootimage,包括创建引导记录、准备initrd映象和相关处理1.4Makefile关键规则和定义描述1.4.1目标定义目标定义是Makefile文件的核心部分,目标定义通知Makefile需要生成哪些目标文件、如何根据特殊的编译选项链接目标文件,同时控制哪些子目录要递归进入进行编译。
这个例子Makefile文件位于/fs/ext2目录:## Makefile for the linux ext2-filesystem routines.#obj-$(CONFIG_EXT2_FS) += ext2.oext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ioctl.o namei.o super.o symlink.oext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.oext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.oext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.oext2-$(CONFIG_EXT2_FS_XIP) += xip.o这表示与ext2相关的目标文件由ext2-y定义的文件列表组成,其中ext2-$(*)是由内核配置文件.config中的配置项决定,最终Makefile会在这个目录下统一生成一个目标文件ext2.o(由obj-$(CONFIG_EXT2_FS)决定)。
其中obj-y表示为生成vmlinux文件所需要的目标文件集合,具体的文件依赖于内核配置。
Makefile会编译所有的$(obj-y)中定义的文件,然后调用链接器将这些文件链接到built-in.o文件中。
最终built-in.o文件通过顶层Makefile链接到vmlinux中。
值得注意的是$(obj-y)的文件顺序很重要。
列表文件可以重复,文件第一次出现时将会链接到built-in.o中,后来出现的同名文件将会被忽略。
文件顺序直接决定了他们被调用的顺序,这一点读者需要特别注意。
读者可能会在某些Makefile中发现lib-y定义,所有包含在lib-y定义中的目标文件都将会被编译到该目录下一个统一的库文件中。
值得注意的是lib-y定义一般被限制在lib 和arch/$(ARCH)/lib 目录中。
体系makefile文件和顶层makefile文件共同定义了如何建立vmlinux文件的规则。
$(head-y) 列举首先链接到vmlinux的对象文件。
$(libs-y) 列举了能够找到lib.a文件的目录。
其余的变量列举了能够找到内嵌对象文件的目录。
$(init-y) 列举的对象位于$(head-y)对象之后。
然后是如下位置顺序:$(core-y), $(libs-y), $(drivers-y) 和$(net-y)。
顶层makefile定义了所有通用目录,arch/$(ARCH)/Makefile文件只需增加体系相关的目录。
例如: #arch/i386/Makefilelibs-y += arch/i386/lib/core-y += arch/i386/kernel/ \arch/i386/mm/ \arch/i386/$(mcore-y)/ \arch/i386/crypto/drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/drivers-$(CONFIG_PCI) += arch/i386/pci/…………………………………………1.4.2目录递归Makefile文件只负责当前目录下的目标文件,子目录中的文件由子目录中的makefile 负责编译,编译系统使用obj-y 和obj-m来自动递归编译各个子目录中的文件。
对于fs/Makefile:obj-$(CONFIG_EXT2_FS) += ext2/如果在内核配置文件.config中,CONFIG_EXT2_FS被设置为y或者m,则内核makefile会自动进入ext2目录来进行编译。
内核Makefile只使用这些信息来决定是否需要编译这个目录,子目录中的makefile规定哪些文件编译为模块,哪些文件编译进内核。
2Kconfig内核源码树的目录下都有两个文档Kconfig和Makefile,分布到各级子目录的Kconfig 构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录下相关的内核配置菜单选项。
在内核配置make menuconfig时,从Kconfig中读出菜单,用户选择后保存到.config 的内核配置文档中。
在内核编译时,顶层Makefile调用这个.config,就知道了用户的选择。
假如要想添加新的驱动到内核的源码中,需要修改Kconfig,这样就能够从配置菜单中选择这个驱动。
假如想使这个驱动被编译,需要修改Makefile。
一个典型的内核配置菜单如下:menu "Network device support"config NETDEVICESbool "Enable Net Devices"depends on NETdefault yhelpThis is help desciption。
...endmenu包含在menu/endmenu中的内容会成为Network device support的子菜单。
每一个子菜单项都是由config来定义的。
congfig下方的那些bool、depends on、default、help等为config 的属性,用于定义该菜单项的类型、依赖项、默认值、帮助信息等。
每个config菜单项都要有类型定义:bool布尔类型、tristate三态(内建、模块、移除)、string字符串、hex十六进制、integer整型。
例如:config HELLO_MODULEbool "hello test module"bool 类型的只能选中或不选中,显示为[ ],tristate类型的菜单项多了编译成内核模块的选项,显示为< >。
假如选择编译成内核模块,则会在.config中生成一个CONFIG_HELLO_MODULE=m的配置;假如选择静态编译,就是直接编译成内核映像,就会在.config中生成一个CONFIG_HELLO_MODULE=y的配置。
hex十六进制类型显示为()。
在Kconfig中有类似语句:source "drivers/usb/Kconfig",用来包含(或嵌套)新的Kconfig 文件,这样便可以使各个目录管理各自的配置内容,不必把那些配置都写在同一个文件里,方便修改和管理。
3模块(module)模块(module)是在内核空间运行的程序,实际上是一种目标对象文件,没有链接,不能独立运行,但是可以装载到系统中作为内核的一部分运行,从而可以动态扩充内核的功能。
模块最主要的用处就是用来实现设备驱动程序。
使用模块的优点:l将来修改内核时,不必全部重新编译整个内核,可节省不少时间l系统中如果需要使用新模块,不必重新编译内核,只要插入相应的模块即可通常,一个Linux内核模块主要由以下几部分组成:(1)module_init()---模块加载函数(必须)当通过insmod或modprobe命令加载内核模块时,模块的加载函数会自动被内核执行,完成模块的相关初始化工作。