驱动程序Makefile解读
在写驱动模块的Makefile是一般都是找一个现成的Makefile更改一下就可以了,该文章主要是为了弄清楚驱动程序的Makefile的原理。
例:一个简单的hello内核模块的Makefile:
#hell0_makefile
ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.koendif
当我们在写完一个模块的Makefile以后,只须要在当前目录下进行make即可。这么make的过程是如何的呢?
1.首先make时,因为make前面没有目标,所以make会将default作为默认的目标文件进执行。
make会执行$(MAKE)-C$(KERNELDIR)M=$(PWD)modules,
#展开为:
make -C /lib/modules/2.6.13-study/build M=/home/study/hello/ modules
可见,make执行了两次。第一次执行时是读hello模块的源代码所在目录/home/study/hello/下的Makefile,第二次执行时是执行/usr/src/linux/下的Makefile时。
第一次make的时侯,KERNELRELEASE未定义linux安装驱动程序,所以走else的分支linux命令chm,步入kernel目录去编译;步入kernel目录编译的时侯会依照M=$(PWD)去$M目录去编译,也就是你make时所在的目录;这时,KERNELRELEASE是被定义过的,所以第二次会走obj-m:=hello.o分支,按照kernel的makefile手指定的规则,会把当前目录下的hello.c编译成hello.o之后生成对应的hello.ko,也就是内核模块。
然而,还是有好多问题
1.KERNELRELEASE并未在驱动的Makefile中定义,那它的作用是哪些?
Makefile中是没有定义这个变量的,所以起作用的是else…endif这一段。不过,假如把hello模块联通到内核源代码中。比如放在/usr/src/linux/driver/中,KERNELRELEASE就有定义了。在/usr/src/linux/Makefile中有KERNELRELEASE的定义,这时侯,hello模块也不再是单独用make编译,而是在内核中用makemodules进行编译。用这些方法,该Makefile在单独编译和作为内核一部份编译时都能正常工作。
2.obj-m:=hello.o哪些时侯执行?
在执行:make-C/lib/modules/2.6.13-study/buildM=/home/study/prog/mod/hello/modules时,make去/usr/src/linux/Makefile中找寻目标modules:
862 .PHONY: modules
863 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
864 @echo ' Building modules, stage 2.';
//调用Makefile.modpost进行第二阶段模块编译
865 $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
可以看出,分两个stage:
1.编译出hello.o文件。
2.生成hello.mod.ohello.ko
在这过程中,会调用make-fscripts/Makefile.build
obj=/home/study/hello
而在scripts/Makefile.build会包含好多文件:include.configinclude$(if$(wildcard$(obj)/Kbuild),$(obj)/Kbuild,$(obj)/Makefile)其中就有/home/study/hello/Makefile这时KERNELRELEASE早已存在。所以执行的是:obj-m:=hello.o
ps:关于makemodules的更详尽的过程可以在scripts/Makefile.modpost文件的注释中找到。假如想查看make的整个执行过程linux安装驱动程序linux设置环境变量,可以运行make-n。