前言
本文的基础是下面两篇博文:
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
等)。