一、Linux 内核模块编译的本质

make modules 命令的执行路径只能是内核源码顶层目录,执行结果是:读取内核源码顶层目录中的 Makefile 文件,找到里面定义的 modules 目标。(更详细的内容不在此处分析)

我们可以建立一个文件夹存放模块源代码,写一个 Makefile,里面写 make modules 目标,但是要切换到 linux 源码目录中找顶层目录的 Makefile 来编译。

# hello 是模块名,也是对应的 c 文件名
obj-m += hello.o
# KDIR 内核源码路径,根据自己需要设置
# X86 源码路径统一是 /lib/modules/$(shell uname -r)/build
# 如果要编译 ARM 的模块,则修改成 ARM 的内核源码路径
KDIR := /home/backvm/work0/linux_ker/linux-3.5.2 
all:
	make -C $(KDIR)  M=$(PWD) modules
	@rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~
clean:
	make -C $(KDIR)  M=$(PWD) modules clean
	rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~

分析:-C 选项的作用是指将当前工作目录转移到你所指定的位置。“M=”选项的作用是,当用户需要以某个内核源码为基础,编译一个外部模块的话,需要在make modules 命令中加入“M=dir”,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成KO文件。


二、示例演示

root@zzz:test# ll
总用量 16
drwxr-xr-x 2 root root 4096 52 13:05 ./
drwxr-xr-x 6 root root 4096 51 19:02 ../
-rw-r--r-- 1 root root  359 51 19:16 hello.c
-rw-r--r-- 1 root root  548 51 19:16 Makefile
root@zzz:test# cat Makefile 
# hello 是模块名,也是对应的 c 文件名
obj-m += hello.o
# KDIR 内核源码路径,根据自己需要设置
# X86 源码路径统一是 /lib/modules/$(shell uname -r)/build
# 如果要编译 ARM 的模块,则修改成 ARM 的内核源码路径
KDIR := /home/backvm/work0/linux_ker/linux-3.5.2 
all:
	make -C $(KDIR)  M=$(PWD) modules
	@rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~
clean:
	make -C $(KDIR)  M=$(PWD) modules clean
	rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~
root@zzz:test# 

三、 linux 多模块编译

如何实现把模块中的一个函数导出给另外一个模块使用?

1) 多模块
EXPORT_SYMBOL(symbol);

这个宏是内核专门用来把一个模块的函数或变量导出,给其他模块使用。
源码示例:

calculate.c 
--------
#include <linux/module.h>
#include <linux/init.h>

static int add_integer(int a,int b);
static int sub_integer(int a,int b);

EXPORT_SYMBOL(add_integer);
EXPORT_SYMBOL(sub_integer);

static int add_integer(int a,int b)
{
	return a+b;
}
static int sub_integer(int a,int b)
{
	return a-b;
}

static int __init hello_init(void)
{
	return 0;
}

static void __exit hello_exit(void)
{
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");


hello.c 
--------
#include <linux/module.h>
#include <linux/init.h>

extern int add_integer(int a,int b);
extern int sub_integer(int a,int b);

static int __init hello_init(void)
{
	int res = add_integer(1,2);
	printk("hello init: res = %d", res);
	return 0;
}

static void __exit hello_exit(void)
{
	int res = sub_integer(1,2);
	printk("hello exit: res = %d", res);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");


Makefile
-------
# hello 是模块名,也是对应的 c 文件名
obj-m += hello.o  calculate.o
# KDIR 内核源码路径,根据自己需要设置
# X86 源码路径统一是 /lib/modules/$(shell uname -r)/build
# 如果要编译 ARM 的模块,则修改成 ARM 的内核源码路径
KDIR := /home/backvm/work0/linux_ker/linux-3.5.2 
all:
	make -C $(KDIR)  M=$(PWD) modules
	@rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~
clean:
	make -C $(KDIR)  M=$(PWD) modules clean
	rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~
root@backvm-virtual-machine:02_export# make
make -C /home/backvm/work0/linux_ker/linux-3.5.2   M=/home/backvm/work0/linux_ker/test/02_export modules
make[1]: Entering directory '/home/backvm/work0/linux_ker/linux-3.5.2'
  CC [M]  /home/backvm/work0/linux_ker/test/02_export/hello.o
  CC [M]  /home/backvm/work0/linux_ker/test/02_export/calculate.o
  Building modules, stage 2.
  MODPOST 2 modules
  CC      /home/backvm/work0/linux_ker/test/02_export/calculate.mod.o
  LD [M]  /home/backvm/work0/linux_ker/test/02_export/calculate.ko
  CC      /home/backvm/work0/linux_ker/test/02_export/hello.mod.o
  LD [M]  /home/backvm/work0/linux_ker/test/02_export/hello.ko
make[1]: Leaving directory '/home/backvm/work0/linux_ker/linux-3.5.2'
root@backvm-virtual-machine:02_export# 
root@backvm-virtual-machine:02_export# modinfo hello.ko 
filename:       /home/backvm/work0/linux_ker/test/02_export/hello.ko
license:        GPL
depends:        calculate
vermagic:       3.5.2 mod_unload ARMv4 p2v8 
root@backvm-virtual-machine:02_export# modinfo calculate.ko 
filename:       /home/backvm/work0/linux_ker/test/02_export/calculate.ko
license:        GPL
depends:        
vermagic:       3.5.2 mod_unload ARMv4 p2v8 
root@backvm-virtual-machine:02_export# 

2) 多文件单模块

多个 c 代码文件编译成一个 ko 文件。
注意:这些文件中只能有一个是以模块的形式编写,其他 c 文件都像普通 c语言文件一样。因为一个模块只能有一个加载函数和一个卸载函数。
Makefile 写法和单文件单模块有点不一样。


Makefile
-------
# hello 是模块名,也是对应的 c 文件名
obj-m +=  mulc.o  # 最终模块名
mulc-objs = hello.o  calculate.o # 源文件列表
# KDIR 内核源码路径,根据自己需要设置
# X86 源码路径统一是 /lib/modules/$(shell uname -r)/build
# 如果要编译 ARM 的模块,则修改成 ARM 的内核源码路径
KDIR := /home/backvm/work0/linux_ker/linux-3.5.2 
all:
	make -C $(KDIR)  M=$(PWD) modules
	@rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~
clean:
	make -C $(KDIR)  M=$(PWD) modules clean
	rm -f  *.o   *.mod.o   *.mod.c  *.symvers *.markers *.unsigned *.order *~



calculate.c 
--------
int add_integer(int a,int b)
{
	return a+b;
}
int sub_integer(int a,int b)
{
	return a-b;
}


hello.c 
--------
#include <linux/module.h>
#include <linux/init.h>

extern int add_integer(int a,int b);
extern int sub_integer(int a,int b);

static int __init hello_init(void)
{
	int res = add_integer(1,2);
	printk("hello init: res = %d", res);
	return 0;
}

static void __exit hello_exit(void)
{
	int res = sub_integer(1,2);
	printk("hello exit: res = %d", res);
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
root@backvm-virtual-machine:02_export_02# make
make -C /home/backvm/work0/linux_ker/linux-3.5.2   M=/home/backvm/work0/linux_ker/test/02_export_02 modules
make[1]: Entering directory '/home/backvm/work0/linux_ker/linux-3.5.2'
  CC [M]  /home/backvm/work0/linux_ker/test/02_export_02/hello.o
  CC [M]  /home/backvm/work0/linux_ker/test/02_export_02/calculate.o
  LD [M]  /home/backvm/work0/linux_ker/test/02_export_02/mulc.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/backvm/work0/linux_ker/test/02_export_02/mulc.mod.o
  LD [M]  /home/backvm/work0/linux_ker/test/02_export_02/mulc.ko
make[1]: Leaving directory '/home/backvm/work0/linux_ker/linux-3.5.2'
root@backvm-virtual-machine:02_export_02# modinfo mulc.ko 
filename:       /home/backvm/work0/linux_ker/test/02_export_02/mulc.ko
license:        GPL
depends:        
vermagic:       3.5.2 mod_unload ARMv4 p2v8 
root@backvm-virtual-machine:02_export_02# 

四、编译所有 linux 文件

make -C $(MOD_SRC_DIR)/$(COMMON_DIR)/$${cpu}/ all
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐