1.2 多个源文件编译成一个内核模块

为什么需要将多个源文件编译到一个内核模块中

在开发比较复杂的驱动时为了提高代码的可读性,方便后期维护升级,往往会采用多个源文件来编写一个驱动,此时便涉及到将多个源文件编译成一个内核模块的问题

实现方法

将多个源文件编译成一个内核模块是通过修改makefile实现,在makefile中可以指定将多个源文件生成的.o文件链接成一个.ko文件。
如下是将module_test.c和module_print.c编译在一个merge_module.ko文件中的makefile

ifeq ($(KERNELRELEASE),)
#第一次执行时 KERNELRELEASE 为空,执行此分支

KERNELDIR ?= /home/lf/workspace/source/my_source/linux/linux-5.4.31
ROOTFS ?= /home/lf/workspace/rootfs
PWD := $(shell pwd)

#$(MAKE) 相当于 make
#-C $(KERNELDIR) 执行 KERNELDIR 目录的Makefile
#M=$(PWD) 内核源码树之外的一个目录
#modules 只编译模块
module:
	$(MAKE) -C $(KERNELDIR) ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- M=$(PWD) modules
copy:
	cp *.ko $(ROOTFS)/root/
install:
	$(MAKE) -C $(KERNELDIR) ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_install
clean:
	rm -rf *.o  .*.cmd *.mod.* *.mod modules.order Module.symvers .tmp_versions
else
#表示要生成 merge_module.ko
	obj-m := merge_module.o
#module.ko 有driver.o和print.o生成
	merge_module-objs = module_test.o module_print.o
endif

与将当个源文件编译为一个.ko的makefile相比,其最大区别便是增加了”merge_module-objs = module_test.o module_print.o“一行
在这里插入图片描述

代码简介

测试代码如下:
在这里插入图片描述
在”module_print.c"中通过了两个函数,分别是“init_print”和“exit_print”,并在"module_print.h"中进行了声明。
module_print.c
module_print.h
在“module_test.c”中提供了模块加载函数和模块卸载函数,并在加载函数中调用了“init_print”,在卸载函数中调用了“exit_print”
在这里插入图片描述

实验

  1. 从“https://gitcode.net/lf282481431/linux_driver_demo/-/tree/master/01-kernel_module/02-module_merge”下载代码,并进行编译,然后拷贝到目标板的root目录中
  2. 执行“insmod merge_module.ko”命令,此时模块被加载,加载函数在输出"module init\r\n"字符串后又调用“init_print”函数输出"module init call back\r\n"字符串
    在这里插入图片描述
  3. 执行“rmmod merge_module.ko”命令,模块被卸载,卸载函数输出"module exit\r\n"字符串后继续调用exit_print函数输出"module exit call back\r\n"字符串
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
多个源文件放在同一个编译模块中,需要进行以下步骤: 1. 创建一个头文件,其中包含所有源文件的函数原型和变量声明,以及必要的宏定义和类型定义。 2. 在每个源文件中,包含这个头文件。 3. 编译每个源文件,生成对应的目标文件。 4. 将所有目标文件链接在一起,生成最终的可执行文件或库文件。 具体实现方式如下: 1. 创建一个头文件(例如,mylib.h),包含所有源文件的函数原型和变量声明,以及必要的宏定义和类型定义。例如: ``` #ifndef MYLIB_H #define MYLIB_H // 函数原型和变量声明 int add(int a, int b); int sub(int a, int b); extern int global_var; #endif // MYLIB_H ``` 2. 在每个源文件中,包含这个头文件,并实现对应的函数和变量。例如,在 add.c 中实现 add 函数: ``` #include "mylib.h" int add(int a, int b) { return a + b; } ``` 在 sub.c 中实现 sub 函数: ``` #include "mylib.h" int sub(int a, int b) { return a - b; } ``` 在 global_var.c 中声明全局变量 global_var: ``` #include "mylib.h" int global_var = 0; ``` 3. 编译每个源文件,生成对应的目标文件。例如,在 Linux 系统下,可以使用以下命令: ``` gcc -c add.c gcc -c sub.c gcc -c global_var.c ``` 4. 将所有目标文件链接在一起,生成最终的可执行文件或库文件。例如,在 Linux 系统下,可以使用以下命令: ``` gcc add.o sub.o global_var.o -o mylib ``` 这样就可以将多个源文件放在同一个编译模块中了,可以方便地进行管理和维护。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值