1、编译进内核的模块
如果需要将foo.ko编译进内核,需要在makefile中进行配置:
obj-y += foo.o
2、编译可加载的模块
如果需要将foo.ko编译成可加载模块,需要在makefile中进行配置:
obj-m += foo.o
obj-m表示编译生成可加载模块。相对应的,obj-y表示直接将模块编译进内核。
3、模块编译依赖多个文件
通常的,驱动开发者也会将单独编译自己开发的驱动模块,当一个驱动模块依赖多个源文件时,需要通过以下方式来指定依赖的文件:
foo-y := a.o b.o c.o
obj-m += foo.o
foo.o 由a.o,b.o,c.o生成,然后调用$(LD) -r 将a.o,b.o,c.o链接成foo.o文件。
注意这里,除了hello-y,同时也可以用hello-objs,实现效果是一样的。即:
foo-objs := a.o b.o c.o
obj-m += foo.o
foo-objs := a.o b.o c.o 表示 foo.o 由a.o,b.o与c.o 连接生成。obj-m := foo.o表示编译连接后将生成foo.ko模块。
4、最简单的makefile
obj-m+=hello.o
all:make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
这个makefile的作用就是编译hello.c文件,最终生成hello.ko文件。
obj-m+=hello.o,这条语句就是显式地将hello.o编译成hello.ko。而hello.o则由make的自动推导功能编译hello.c文件生成。
-C选项:此选项指定make在编译时将会进入指定的目录(内核源码目录)。
modules是将源文件编译并生成内核模块。
$(KDIR):/lib/modules/(shell uname -r)/build/,指定内核源码的位置。
M=$(PWD):需要编译的模块源文件地址。
5、linux内核模块编译makefile
通常,标准的Kbuild-Makefile
会写成这样:
ifneq ($(KERNELRELEASE),)obj-m := hello.oelseKDIR ?= /lib/modules/`uname -r`/buildall:$(MAKE) -C $(KDIR) M=$(PWD) modules // -C:表示change,change到内核源码里面去编译, M=$( ):指定了要编译驱动的源码目录;// 因此就该程序会再次进入我们这个makefile文件进行执行,接下来继续去判断 KERNELRELEASE 变量
clean:$(MAKE) -C $(KDIR) M=$(PWD) clean
endif
ifneq (a,b) #如果a和b不相等,执行这句。
else #否则,执行这句。
从Linux内核2.6开始,Linux内核的编译采用Kbuild系统,这同过去的编译系统有很大的不同, 尤其对于Linux内核模块的编译。在新的系统下,Linux编译系统会两次扫描Linux的Makefile:首先编译系统会读取Linux内核顶层的 Makefile,然后根据读到的内容第二次读取Kbuild的Makefile来编译Linux内核。
需要注意的一个基本概念是:每一次编译,顶层makefile都试图递归地进入每个子目录调用子目录的makefile,只是当目标子目录中没有任何修改时,默认不再进行重复编译以节省编译时间。
- 首次执行当前标准的
Kbuild-Makefile
时,KERNELRELEASE并没有被定义,所以走else分支,直接执行
$(MAKE) -C $(KDIR) M=$(PWD) modules
-
而这条指令会进入到$(KDIR)目录,调用顶层的
Kernel Makefile
,在顶层makefile中定义了KERNELRELEASE变量。 -
顶层makefile都试图递归地进入每个子目录调用子目录的
Kbuild-Makefile
,只是当目标子目录中没有任何修改时,默认不再进行重复编译以节省编译时间。 在这一时刻只有M=$(PWD)
需要编译。 -
在顶层makefile中会递归地再次调用到当前目录下的makefile文件,这时KERNELRELEASE变量已经非空,所以执行if分支,
在可加载模块编译列表添加hello模块,由此将模块编译成可加载模块放在当前目录下。
obj-m := hello.o这句话是给内核使用,他会收集内核驱动的binary文件,最终生成.ko的驱动文件。 这个Makefile会进来两次,第一次编译内核 第二次生成.ko文件。
归根结底,各级子目录中的makefile文件的作用就是先切换到顶层makefile,然后通过obj-m在可加载模块编译列表中添加当前模块,kbuild-makefile就会将其编译成可加载模块。如果是直接编译整个内核源码,就省去了else分支中进入顶层makefile的步骤。
参考链接:
linux内核模块编译makefile
KBuild MakeFile介绍
Linux内核Makefile介绍
linux字符设备驱动 Makefile分析obj-m := helloDev.o