写这篇文章,主要是为了记录一下工作中用到的一些技术、协议等等,随时填充一些细节,方便后续需要,不用再到处找资料了。如有错误的地方,希望各位大佬予以指教!
项目中需要开发linux字符设备驱动,需要把批量的C文件编译成ko文件,下面来记录一下makefile的原理。
linux内核的编译系统kbuild,他通过预定义变量(obj-m、-objs等)和目标,用户只需为这些变量赋值,kbuild就可以自动把代码编译成模块(或编译到内核中)。
makefile基本格式
这是一个最简易的makefile,其含义是把hello.c文件编译为ko文件。
obj-m := hello.o
kernel_modules:
$(MAKE) -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
obj-m := 模块名.o
obj-m表示把文件hello.o作为"模块"进行编译,不会编译进内核,但是会生成一个独立的 “hello.ko” 文件。而obj-y则是直接编译进内核。makefile具有自动推导功能,在该代码中只提供了hello.o文件,我们直接执行make时,它会自动推导.o所需的C文件,它默认在当前目录下查找C文件,然后再生成.o以及.ko文件
KERNELDIR := /lib/modules/4.1.15+/build
CURRENT_PATH := $(shell pwd)
MODULE_NAME :=hello
obj-m := hello.o
hello-objs := hello1.o hello2.o hello3.o hello4.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
在Makefile文件中,首先定义了KERNELDIR,它指的是内核库文件的路径,构造内核树时,内核库统一保存在/lib/modules/内核版本号/build
目录下。
KERNELDIR := /lib/modules/4.1.15+/build
将shell pwd作为变量,把$(shell pwd)
表示为CURRENT_PATH,后续方便调用,shell pwd意为获取当前下的路径。
CURRENT_PATH := $(shell pwd)
//定义模块名为hello
MODULE_NAME :=hello
obj-m表示把文件hello.o作为"模块"进行编译,不会编译到内核,但是会生成一个独立的 “hello.ko” 文件。如果有多个文件编译则需要添加hello-objs,如下:
obj-m := hello.o
hello-objs := hello1.o hello2.o hello3.o hello4.o
这一行的作用是,到kernel_modules这一段去执行编译的操作。
build: kernel_modules
-C选项表示的是跳转到指定路径下并读取该路径下的Makefile,即转移至(KERNELDIR)
的位置(内核源代码目录),M=$(CURRENT_PATH)
表示返回到当前路径并继续执行当前的Makefile。modules 指明编译的目标是生成内核模块.ko
文件。
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean以下代码含义是清除掉make过程中生成的所有文件
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
装载内核模块命令:insmod hello.ko
卸载内核模块命令:rmmod hello.ko
查看当前安装的内核模块命令:lsmod