前言
本文的基础是下面两篇博文:
https://blog.csdn.net/wenhao_ir/article/details/144556756
https://blog.csdn.net/wenhao_ir/article/details/144532544
本篇博文对应的学习实例是:
https://blog.csdn.net/wenhao_ir/article/details/144881830
源码
编译驱动程序模块和测试程序的Makefile的源码如下:
# 使用不同的Linux内核时, 一定要修改KERN_DIR,KERN_DIR代表已经配置、编译好的Linux源码的根目录KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88all:make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c clean:make -C $(KERN_DIR) M=`pwd` cleanrm -rf modules.orderrm -f hello_drv_testobj-m += hello_drv.o
如何配置、编译Linux源码
上面Makefile文件的第一行显示,KERN_DIR代表已经配置、编译好的Linux源码的根目录,那么问题来了,怎么样配置、编译Linux的源码呢?请参考我的另一篇博文:
https://blog.csdn.net/wenhao_ir/article/details/144421577
语句make -C $(KERN_DIR) M=pwd modules
make -C $(KERN_DIR) M=`pwd` modules
这句话是一句 make 命令,具体解释如下:
-
make是一个构建工具,用于自动化编译过程。 -
-C $(KERN_DIR):这个选项告诉make在指定的目录$(KERN_DIR)中运行make,即进入$(KERN_DIR)指定的目录( Linux 内核的源码目录),执行该目录下的 Makefile 中定义的规则。 -
M=pwd``:这个部分设置了make的一个变量M,它被赋值为当前工作目录的路径。pwd是一个 shell 命令,用于返回当前目录的路径。因此,M=$(pwd)会将当前目录(假设是模块源码所在目录)赋值给M。 -
modules:这是要传递给make的目标,表示要编译内核模块。
综上所述,make -C $(KERN_DIR) M=pwd modules 这条命令的作用是:
- 在指定的 Linux 内核源码目录
$(KERN_DIR)中运行make。 - 通过下面这个参数:
M=`pwd`
将当前目录(模块源码目录)传递给内核源码目录中的 Makefile,使得内核编译系统能够找到并编译该目录中的内核模块(即编译 hello_drv.o 这样的模块)。
语句$(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c
$(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c
这句话就没啥好说的了,就是一条普通的交叉编译命令,表示把文件hello_drv_test.c编译生成ELF可执行文件hello_drv_test hello
语句make -C $(KERN_DIR) M=pwd clean
make -C $(KERN_DIR) M=`pwd` clean
值得注意的是,教程官方提供的Makefile这里为:
make -C $(KERN_DIR) M=`pwd` modules clean
这里面的modules显然是多余的,加这modules的话这句话是先执行构建,再清除,本来我的目标就是要清除构建中产生的相关文件,我先去执行一次构建没有任何意义,所以应该去掉这里的modules。
语句分解:
-
make:
调用make工具,执行构建或清理任务。 -
-C $(KERN_DIR):
指定工作目录,make会先切换到$(KERN_DIR)所指的目录(通常是内核源码的根目录)并执行该目录下的Makefile。 -
**
M=\pwd`**: 将当前目录的路径(由pwd命令返回)赋值给M变量。M` 是内核构建系统中的一个约定变量,用来指定外部模块的源码目录。
这一参数的作用是告诉内核构建系统,只针对当前目录中的模块进行操作。 -
clean:
clean是 Makefile 中的一个目标,用于清理模块编译时生成的临时文件(如.o文件、依赖文件等)。当目标为clean时,内核构建系统会删除与模块相关的构建产物,而不会重新编译模块。
整体含义:
make -C $(KERN_DIR) M=\pwd` clean` 的作用是:
- 切换到指定的 Linux 内核源码目录
$(KERN_DIR)。 - 执行内核构建系统中的
clean目标。 - 仅清理当前目录(
pwd返回的目录)下的模块构建文件,而不会影响内核源码目录的其他部分。
示例应用场景:
当你在开发外部内核模块(如 hello_drv.c)时,需要清除模块编译过程中生成的临时文件,比如 .o、.ko、.mod.c 等文件,可以使用这条命令。它保证仅清理当前模块的文件,而不会干扰整个内核的其他内容。
语句obj-m += hello_drv.o
obj-m += hello_drv.o
含义分解:
-
obj-m:- 这是内核模块编译系统的一个变量,用于指定要编译的外部模块(
m表示模块类型)。 obj-m列表中每个.o文件都会被编译成内核模块(.ko文件)。
- 这是内核模块编译系统的一个变量,用于指定要编译的外部模块(
-
+=:- 将
hello_drv.o添加到obj-m列表中。 - 如果之前
obj-m中已经有其他模块,这种方式可以追加新模块,而不会覆盖之前的内容。
- 将
-
hello_drv.o:- 表示模块的目标文件,内核构建系统会根据此名称找到相应的
hello_drv.c源文件。 - 编译完成后会生成对应的
.ko文件(hello_drv.ko),这是加载到内核中的模块文件。
- 表示模块的目标文件,内核构建系统会根据此名称找到相应的
整体作用
obj-m += hello_drv.o 的作用是告诉内核模块编译系统,当前目录中的 hello_drv.c 文件需要被编译成模块文件 hello_drv.ko。
编译流程
- 内核模块的构建由内核的构建系统完成,
Makefile使用obj-m变量告诉系统要编译哪些模块。 - 执行
make -C $(KERN_DIR) M=\pwd` modules` 时:- 内核构建系统会读取当前目录下的 Makefile。
- 根据
obj-m的设置,找到hello_drv.c文件并开始编译。 - 编译完成后生成:
hello_drv.ko(模块文件)- 其他辅助文件(如
.o、.mod.c、.symvers等)。
