通常,一个linux内核模块的makefile写法都是如下所示:
-
# If KERNELRELEASE is defined, we've been invoked from the
-
# kernel build system and can use its language.
-
ifneq ($(KERNELRELEASE),)
-
obj-m := hello.o
-
# Otherwise we were called directly from the command
-
# line; invoke the kernel build system.
-
else
-
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
-
PWD := $(shell pwd)
-
default:
-
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
-
endif
我一直都很好奇,为什么要用if将代码分开,而不是干脆使用里面的所有代码呢?而且看起来if-else将其分割成两部分,default目标也不知道将要编译成的模块的名字啊,但是编译模块时又能得到我们所指定的模块名字,那么这又是为什么呢?
最近开始阅读《Linux设备驱动》第三版,在第二章“building and installing modules”(英文版P24),终于找到了答案。
原来是因为kbuild系统的设计,首先在源码目录下,
$(KERNELRELEASE)没有定义,所以makefile中第二行:
-
ifneq ($(KERNELRELEASE),)
不满足条件,所以走else分支,声明了$
KERNELDIR以及$PWD变量,并在default中开始编译。-C选项跳转进入内核树目录,kbuild会重新读取一次makefile,此时$(KERNELRELEASE)已经定义,于是声明内核模块名字:
-
obj-m := hello.o
读取到正确的模块名字后,重新开始编译构建,并得到最终的模块。
综上所述,所有的这一切都归功于内核的kbuild系统,其最巧妙的地方在于两次读取makefile,从而使我们平常认为不可能同时作用的ifneq-else-endif结构中的两个分支中的语句同时发生作用,也就相当于没有了这个ifneq-else-endif结构的限制。于是自然就能得到所需要的全部信息。
而这,就是内核kbuild系统的特殊机制。
阅读(3993) | 评论(0) | 转发(0) |