Linux 驱动开发之内核模块开发——内核模块编译 Makefile 入门

文章详细介绍了Linux驱动的动态编译,包括静态编译和动态编译(内部和外部编译)的区别。重点讲解了动态编译中的外部编译过程,提到了makefile的关键变量如KERNELRELEASE、KDIR、PWD的含义及作用,并阐述了make执行的步骤。此外,还提及了多文件编译的方法以及内部编译的情况,即驱动模块整合到内核源码中进行编译。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 模块的编译

驱动编译分为静态编译动态编译静态编译即为将驱动直接编译进内核,动态编译即为将驱动编译成模块。

而动态编译又分为两种:
(1)内部编译
在内核源码目录内编译
(2)外部编译
在内核源码的目录外编译

2. 具体编译过程分析

注:本次编译是外部编译,使用的内核源码是Ubuntu 的源代码,而非开发板所用linux 3.14内核源码,运行平台为X86。

对于一个普通的linux设备驱动模块,以下是一个经典的makefile代码,使用下面这个makefile可以完成大部分驱动的编译,使用时只需要修改一下要编译生成的驱动名称即可。只需修改obj-m的值。

ifneq  ($(KERNELRELEASE),)
obj-m:=hello.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
    make -C $(KDIR) M=$(PWD) modules
clean:
    rm -f *.ko *.o *.symvers *.cmd *.cmd.o
endif

2.1 makefile 中的变量

先说明以下makefile中一些变量意义:
(1)KERNELRELEASE在内核源码树的Makefile中定义,在当前的Makefile中,它的值为空
(2)$(shell uname-r)获得当系统的Linux内核版本
(3)shell pwd取得当前工作路径
(4)KDIR制定当前Linux操作系统源代码路径,即编译生成的模块是在当前系统中使用。如果想将你写的模块,用在你的开发板上运行的Linux系统中,只需在KDIR变量中指定你开发板Linux系统源码树的路径。

关于linux源码的目录有两个,分别为:
/lib/modules/$(shell uname -r)/build

/usr/src/linux-header-$(shell uname -r)/

但如果编译过内核就会知道,usr目录下那个源代码一般是我们自己下载后解压的,lib目录下的则是在编译时自动copy过去的,两者的文件结构完全一样,因此有时也将内核源码目录设置成/usr/src/linux-header-$(shell uname -r)/。关于内核源码目录可以根据自己的存放位置进行修改。

(5)make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
这就是编译模块了:

1)首先改变目录到-C选项指定的位置(即内核源代码目录),其中保存有内核的顶层makefile

2)M= 选项让该makefile在构造modules目标之前返回到模块源代码目录;然后,modueles目标指向obj-m变量中设定的模块;在上面的例子中,我们将该变量设置成了hello.o

2.2 make 的的执行步骤

(1)在模块的源代码目录下执行make,此时,宏“KERNELRELEASE”【内核源码树的Makefile会定义】没有定义,因此进入else;

(2)记录内核路径KDIR和当前工作目录PWD;

由于make 后面没有目标,所以make会在Makefile中的第一个不是以.开头的目标作为默认的目标执行。默认执行all这个规则。

(3)make -C $(KDIR) M=$(PWD) modules
-C 进入到内核的目录执行Makefile ,在执行的时候KERNELRELEASE就会被赋值,M=$(PWD)表示返回当前目录,再次执行makefile,modules 编译成模块的意思

所以这里实际运行的是:

make -C /lib/modules/2.6.13-study/build M=/home/fs/code/1/module/hello/ modules

(4)再次执行该makefileKERNELRELEASE就有值了,就会执行obj-m:=hello.o

obj-m表示会将hello.o目标编译成.ko模块;它告诉linux源码树顶层Makefile是动态编译(编译成模块)而不是编译进内核(obj-y),linux源码树顶层Makefile会根据hello.o找到hello.c文件。

可以看出make在这里一共调用了3次

1)make
2)linux内核源码树的顶层makedile调用,产生.o文件
3)linux内核源码树makefile调用,把.o文件链接成.ko文件

2.3 编译多文件

若有多个源文件,则采用如下方法:

obj-m := hello.o
hello-objs := file1.o file2.o file3.o

3. 内部编译简单说明

如果把hello模块移动到内核源代码中。例如放到/usr/src/linux/driver/中, KERNELRELEASE就有定义了。

/usr/src/linux/Makefile中有

KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)$(LOCALVERSION)

这时候,hello模块也不再是单独用make编译,而是在内核中用make modules进行编译,此时驱动模块便和内核编译在一起。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值