Linux中多个.c文件编译为一个模块.ko

例如现在有三个文件:

exp.c

exps.c

exp.h

这是目前做实验的代码,其中exps中是工具函数,其内容被exp.c调用,exp.h是exps.c文件中函数的声明以及一些结构体的定义。

下面介绍将exp.c与exps.c编译为一个模块ex.ko,以及在这个过程中遇到的一系列问题。

由于exps.c中是一些工具函数,所以在exps.c中不需要module_init、module_exit等来进行修饰,而exp.c要调用exps.c,并且里面含有模块的入口函数和出口函数,所以在exp.c中使用module_init、module_exit等模块结构。

一个模块只有一个入口和出口,所以只有一对module_init、module_exit,同时要添加上MODULE_LICENSE("GPL")

实验代码不方便贴出来,但是方法已经过真机测试,现在在我的虚拟机上随便写几个函数来演示一下:

exp.c:

#include 
#include 
#include 
#include "exp.h"

extern void exps_init(int e);

static int table_init(void)
{
	printk("TABLE: table init \n");
	exps_init(50);   
	return 0;
}

static void table_exit(void)
{
	printk("TABLE: table exit \n");
}

module_init(table_init);
module_exit(table_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Me");
MODULE_DESCRIPTION("module test");

extern导入符号是必要的,测试了如果不导入符号,会报如下错误:

error: implicit declaration of function ‘exps_init’ [-Werror=implicit-function-declaration]

即使这句extern 写在exp.h中也不行。

exps.c:

#include "exp.h"
#include 

void print(int e)
{
	printk("parameter is %d \n",e);
}

void exps_init(int e)
{
	printk("hello, this is exps \n");
	print(e);	
}

在exps.c中,符号exps_init会被exp.c调用,这里既可以使用EXPORT_SYMBOL来导出这个符号,也可以不使用EXPORT_SYMBOL,测试了都没有问题。

exp.h:

#ifndef _LINUX_EXP_COMMON_H_
#define _LINUX_EXP_COMMON_H_

void exps_int(int e);

#endif

Makefile:

ifneq ($(KERNELRELEASE),)
obj-m:=ex.o
ex-objs:=exp.o exps.o
else
 
#generate the path
CURRENT_PATH:=$(shell pwd)
CONFIG_MODULE_SIG = n
#the absolute path
LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build

#complie object
default:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
endif

Makefile是关键,首先 obj-m指定模块名,然后再根据模块名-objs:=依赖的文件。

最开始我想将模块名设置为exp,但是和我的文件重名了,这时候编译虽然成功了,但是插入模块会报如下错误:

[ 2045.410335] exp: module license 'unspecified' taints kernel.
[ 2045.410338] Disabling lock debugging due to kernel taint

所以我不能选择exp或者exps作为模块名~

依赖文件不需要顺序,比如既可以是:

ex-objs:=exp.o exps.o

也可以是:

ex-objs:=exps.o exp.o

使用make编译得到如下内容:

insmod 插入模块后,dmesg就可以得到想要的信息:

Linux中多个.c文件编译为一个模块.ko_第1张图片

 

多个文件:

多个文件也是一样,比如这里我再增加了一个expss.c文件,该文件中函数expss_init被exps.c中函数调用:

此时exps.c:

#include "exp.h"
#include 

extern int expss_init(int e);

void print(int e)
{
	printk("parameter is %d \n",e);
}

void exps_init(int e)
{
	printk("hello, this is exps \n");
	e = expss_init(e);
	print(e);	
}

expss.c:

#include 
#include "exp.h"

int expss_init(int e)
{
	return (e+10);
}

Makefile:

ifneq ($(KERNELRELEASE),)
obj-m:=ex.o
ex-objs:=expss.o exps.o exp.o 
else
 
#generate the path
CURRENT_PATH:=$(shell pwd)
CONFIG_MODULE_SIG = n
#the absolute path
LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build

#complie object
default:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
endif

编译出文件如下:

插入模块运行如下:

Linux中多个.c文件编译为一个模块.ko_第2张图片

你可能感兴趣的:(Linux)