Linux驱动程序Makefile文件见解

515 阅读2分钟

一个简单驱动的makefile文件

#mydev_makefile
ifneq ($(KERNELRELEASE),)
obj-m:=mydev.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

  • obj-m :这个变量是指定你要声称哪些模块,模块的格式为 obj-m := <模块名>.o 。上面代码表示把文件mydev.o作为"模块"进行编译,不会编译到内核,但是会生成一个独立的 "mydev.ko" 文件;

  • obj-y:表示把test.o文件编译进内核;

  • KERNELDIR:内核库文件的路径,代码中使用的是内核提供的函数。而这些函数也是有具体实现的,在连接成一个内核模块时要说明这些库文件在哪里,方便链接程序把它们连接成一个完整的模块。

  • KERNELDIR=/lib/modules/$(shell uname -r)/build;其中 shell uname -r 说的是调用shell里头的uname指令,你可以uname -r看看,他表示的是内核版本号,一般来说我们构造内核树时,它把内核库统一保存在/lib/modules/内核版本号/build目录下。

  • PWD :这是当前工作路径。将shell pwd作为变量,通过 $(shell pwd)形式引用这个变量

  • M= :指定我们源文件的位置

当我们在写完一个模块的Makefile之后,只需要在当前目录下进行make即可。

make时,由于make后面没有目标,所以make会将default作为默认的目标文件进执行。make会执行  \$(MAKE) -C $( KERNELDIR) M= \$(PWD) modules

  • -C $(KERNELDIR):指定进入指定的目录即KERNELDIR,是内核源代码目录,调用该目录顶层下的Makefile;
  • M= $(PWD):通过shell命令(pwd命令)获取当前目录,而M不是makefile的选项,是内核根目录下的Makefile中使用的变量。作用是让该Makefile在构造modules目标之前返回到模块源代码目录并在当前目录生成obj-m指定的xxx.o目标模块
make的过程

第一次make的时候,KERNELRELEASE未定义,所以走else的分支,进入kernel目录去编译;进入kernel目录编译的时候会根据M= \$ (PWD)$M目录去编译,也就是你make时所在的目录;这时,KERNELRELEASE是被定义过的,所以第二次会走obj-m:=hello.o分支,根据kernel的makefile中指定的规则,会把当前目录下的hello.c编译成hello.o然后生成对应的hello.ko,也就是内核模块。

扩展

$(MAKE) -C $(KERNELDIR) M=\$(PWD) modules #ARCH=riscv CROSS_COMPILE=riscv64-buildroot-linux-gnu-

  • arch: 即architecture,就是选择编译哪一种cpu,也就是编译arch/目录下的哪一个子目录。如指定make ARCH=arm就是编译arch/arm下的代码。如果不指定,make将使用本机(用什么机器编译就是什么)的cpu作为缺省ARCH。注意:arch/arm下不但有arm体系架构特有的代码,还有arm特有的kconfig,也就是配置选项,所以在make menuconfig,make xxxx\_defconfig的时候也必须指定ARCH=arm。
  • CROSS_COMPILE:即交叉编译器的前缀(prefix),也就是选择将代码编译成目标cpu的指令的工具,如指定make CROSS_COMPILE=arm-none-linux-gnueabi-就是使用arm-none-linux-gnueabi-gcc, arm-none-linux-gnueabi-ld等工具将代码编译成arm的可执行指令。如果不指定CROSS_COMPILE参数,make时将认为prefix为空,即使用gcc来编译。这里cross_compile的设置,是假定所用的交叉工具链的gcc程序名称为arm-linux-gcc。如果实际使用的gcc名称是some-thing-else-gcc,则这里照葫芦画瓢填some-thing-else-即可。总之,要省去名称中最后的gcc那3个字母。