1. linux2.6内核Makefile简单语法与应用
1.1 概述
2.6的Makefile的写法和应用相对于2.4有了一些变化,可能对于很多人来说,因为找不到相关的文档,都是模仿内核中已有的文件来写自己的Makefile。其实,在内核的Documentation/kbuild(这个目录下的文档值得深究,对了解内核编译有很大的用处)目录下面,有对内核Makefile语法的详细说明。在这里就2.6内核中Makefile最常见的简单应用情况做一个翻译和归纳介绍。
2.6内核的Makefile分为5个组成部分:
1. 最顶层的Makefile
2. 内核的.config配置文件
3. 在arch/$(ARCH) 目录下的体系结构相关的Makefile
4. 在scripts/ 目录下的 Makefile.* 文件,是一些Makefile的通用规则
5. 各级目录下的大概约500个kbuild Makefile文件
顶层的Makefile文件读取.config文件的内容,并总体上负责build内核和模块。Arch Makefile则提供补充体系结构相关的信息。 Scripts目录下的Makefile文件包含了所有用来根据kbuild Makefile 构建内核所需的定义和规则。
1.2 Kbuild Makefile
目标定义就是用来定义哪些内容要做为模块编译,哪些要编译链接进内核。
例如
- obj-y += foo.o
表示要由foo.c或者foo.s文件编译得到foo.o并链接进内核,而obj-m则表示该文件要作为模块编译。 除了y,m以
- obj-$(CONFIG_ISDN) += isdn.o
- obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
最简单的kbuild Makefile如上一节一句话的形式就够了,如果一个模块由多个源文件组成,那么稍微复杂一些,采用模块名加 -objs后缀或者 -y后缀的形式来定义模块的组成文件。如以下例子:
- obj-$(CONFIG_EXT2_FS) += ext2.o
- ext2-y := balloc.o bitmap.o
- ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
- obj-$(CONFIG_ISDN) += isdn.o
- isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
如下例:
- obj-$(CONFIG_EXT2_FS) += ext2/
编译模块的时候,你可以将模块放在代码树中,用Make modules的方式来编译你的模块,你也可以将模块相关文
- make -C path/to/kernel/src M=$PWD modules
-C指定代码树的位置,M=$PWD 或 M=`PWD` 告诉kbuild回到当前目录来执行build操作。对于交叉编译环境为:
- $(MAKE) ARCH=arm CROSS_COMPILE=arm-linux- -C $(KERNELDIR) M=$(PWD) modules
1.2.5 模块的安装
当你需要将模块安装到非默认位置的时候,你可以用INSTALL_MOD_PATH 指定一个前缀,如:
- make INSTALL_MOD_PATH=/foo modules_install
模块将被安装到 /foo/lib/modules目录下。
2. 内核静态库的使用
在驱动程序里面编译链接内核静态库需要从三个方面注意:
1. 首先保证你正确生成了内核静态库文件,而非应用程序库文件;
2. 其次是除去静态库之外的驱动文件的正确性,包括内核库函数的调用和头文件的申明;
3. 正确修改驱动的Makefile;
这几个方面都正确之后,就能正确地将内核库编译进指定的驱动中去。
2.1编译内核静态库文件
模块代码目录结构如下:
|
driver.c |
|
|
Makefile |
|
|
lib |
myalib.c |
|
myalib.c | |
|
Makefile |
内核静态库包含一个myalib.c和myalib.h文件,代码如下:
- //myalib.c
- void test(void)
- {
- printk("A lib test.\n");
- }
- //myalib.h
- void test(void);
- # This is the Makefile for parse.
- RM = rm -f
- CCFLAGS = -c
- ARFLAG = -rc
- CC = gcc
- AR = ar
- lib_OBJECTS = myalib.o
- lib_SOURCE = myalib.c
- LIB = libtest.a
- libtest.a:$(lib_OBJECTS)
- $(AR) $(ARFLAG) -o $@ $^
- $(lib_OBJECTS):$(lib_SOURCE)
- $(CC) $(CCFLAGS) -o $@ $^
- clean:
- $(RM) $(lib_OBJECTS)
- $(RM) $(LIB)
在输入终端下执行”make”命令即可生成正确的内核库libtest.a文件
2.2 链接内核静态库文件
驱动代码包括一个driver.c文件。
- #include <linux/init.h>
- #include <linux/module.h>
- #include "./lib/myalib.h" //如果这里不加lib,那么需要在Makefile中添加EXTRA_CFLAGS += -I$(绝对路径)
- MODULE_LICENSE("Dual BSD/GPL");
- int init_module(void)
- {
- printk("into init_module.\n");
- test();
- return 0;
- }
- void cleanup_module(void)
- {
- printk("into cleanup_module.\n");
- test();
- }
可以看到,在驱动初始化中调用了库文件中的test()函数,并且包含其头文件。
2.3 Makefile的修改
修改驱动Makefile文件,加入内核库文件的编译链接。
这个地方的修改比较简单,只需内核库文件当做.o文件一样去进行编译链接即可。
- # Makefile
- KERNELRELEASE=
- ifneq ($(KERNELRELEASE),)
- obj-m := drv.o
- drv-objs := driver.o lib/libtest.a
- else
- KDIR := /lib/modules/$(shell uname -r)/build
- PWD := $(shell pwd)
- $(OBJDIR)/%.o: $(SRCDIR)/%.c
- $(CC) -o $@ $(CFLAGS) -c $<
- default:
- $(MAKE) -C $(KDIR) M=$(PWD) modules
- clean:
- rm -f *.o *.ko *.o.cmd *.mod.c *.symvers
- endif
注意添加的lib/libtest.a
OK,最后终端下执行”make”命令即可成功地将内核库文件和目标驱动文件链接到一起。然后就可以装载驱动进行验证了。
最后需要说明一下,以上只是个最简单的演示版代码,在这个基础上,大家可以根据自己的需要丰富内核库和驱动的内容,从而达到真正的项目用途的目的。