序言
从Linux内核2.6开始,Linux内核的编译采用Kbuild系统,这同过去的编译系统有很大的不同,尤其对于Linux内核模块的编译。在新的系统下,Linux编译系统会两次扫描Linux的Makefile:首先编译系统会读取Linux内核顶层的Makefile,然后根据读到的内容第二次读取Kbuild的Makefile来编译Linux内核。
Linux内核Makefile分类
- Kernel Makefile
- Kbuild Makefile
- ARCH Makefile
Kbuild Makefile
Kbuild Makefile的文件名不一定是Makefile,尽管推荐使用Makefile这个名字。大多的Kbuild文件的名字都是Makefile。为了与其他Makefile文件相区别,你也可以指定Kbuild Makefile的名字为Kbuild。而且如果“Makefile”和“Kbuild”文件同时存在,则Kbuild系统会使用“Kbuild”文件。
- 目标定义
- obj-?
obj-? = $(target).o
target为编译对象的名字。如果没有指定xxx-objs,这编译这个对象需要的源文件就是$(target).c或$(target).s。如果指定了$(target)-objs,则编译这个对象需要的源文件由$(target)-objs指定,并且不能有$(target).c或$(target).s文件。
- xxx-objs
- 嵌套编译
有时一个对象可能嵌入到另一个对象的目录下,那个如何编译子目录下的对象呢?其实很简单,只要指定obj_?的对象为子目录的名字就可以了:
obj-? = $(sub_target)/
- 编译器选项
- ccflags-y, asflags-y and ldflags-y
编译外部模块
有时候我们需要在内核源代码数的外面编译内核模块,编译的基本命令是:
make -C $(KERNEL_DIR) M=`pwd` modules
我们可以把这个命令集成到Makefile里,这样我们就可以只输入“make”命令就可以了。回想上一章的那个Makefile,它把Normal Makefile 和Kbuild Makefile集成到一个文件中了。为了区别Kbuild Makefile 和Normal Makefile,这样我们改写Makefile为如下形式,并且添加Kbuild Makefile - “Kbuild”。
##Makefile ifneq ($(KERNELRELEASE),) include "Kbuild" else KERNEL_DIR = /lib/modules/`uname -r`/build MODULEDIR := $(shell pwd) .PHONY: modules modules: clean distclean: |
## Kbuild MODULE_NAME = helloworld $(MODULE_NAME)-objs := hello.o obj-m := $(MODULE_NAME).o |
一般不需要在Makefile里包含如下代码,这样写完全是为了兼容老版本的Kbuild系统。KERNELRELEASE变量在Kernel Makefile里定义的,因此只有在第二次由Kbuild读取这个Makefile文件时才会解析到Kbuild的内容。
ifneq ($(KERNELRELEASE),) include "Kbuild" else ... endif |
外部头文件
有时需要连接内核源代码外部的系统头文件,但Kbuild系统默认的系统头文件都在内核源代码内部,如何使用外部的头文件呢?这个可以借助于Kbuild系统的特殊规则:
- EXTRA_CFLAGS
EXTRA_CFLAGS += $(ext_include_path)
一般外部头文件可能位于外部模块源文件的目录内,如何指定呢?这可以借助$(src)或$(obj)
- $(src)/$(obj)
因此,我们修改Kbuild文件添加 EXTRA_CFLAGS 来包含外部头文件尽管在这个驱动里没有引用外部系统头文件:
## Kbuild MODULE_NAME = helloworld $(MODULE_NAME)-objs := hello.o EXTRA_CFLAGS := -I$(src)/include obj-m := $(MODULE_NAME).o |
后记
这里我们详细的介绍了Linux内核的Kbuild系统,相信你已经可以自如的写自己的Kbuild Makefile了。现在开始,我们就可以写带有一些功能的驱动程序了。Linux里的驱动程序可以分为三类,字符设备驱动程序,块设备驱动程序和网络设备驱动程序。在后面的章节里你会详细的了解到这些驱动程序,同时可以了解到Linux内核里用到的一些技术,如进程管理、内存管理、内核同步技术、内核时钟等。