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 5月 2 13:05 ./
drwxr-xr-x 6 root root 4096 5月 1 19:02 ../
-rw-r--r-- 1 root root 359 5月 1 19:16 hello.c
-rw-r--r-- 1 root root 548 5月 1 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#
如何实现把模块中的一个函数导出给另外一个模块使用?
EXPORT_SYMBOL(symbol);
这个宏是内核专门用来把一个模块的函数或变量导出,给其他模块使用。
源码示例:
calculate.c
--------
#include
#include
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
#include
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#
多个 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
#include
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#
make -C $(MOD_SRC_DIR)/$(COMMON_DIR)/$${cpu}/ all