linux make modules 命令详解


一、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
模块一般用来支持那些不经常使用的功能。例如,通常情况下你仅使用拨号网络,因此网络功能并不是任何时候都需要的,那么就应该使用可装入的模块来提供这个功能。仅在你进行拨号联接的时候,该模块才被装入。而在你断掉连接的时候它会被自动卸下。这样会使内核使用内存的量最小,减小系统的负荷。 当然,那些象硬盘访问这样时时刻刻都需要的功能,则必须作在内核里。如果你搭一台网络工作站或 web服务器,那么网络功能是时刻都需要的,你就应该考虑把网络功能编译到内核里。另外一个方法是在启动的时候就装入网络模块。这种方法的优点是你不需要重新编译内核。而缺点是网络功能不能特别高效。 按照以上的原则,我们首先列出一张清单,看看 kernel 中哪些选项是非有不可的,也就是说,这些东西是必须被编译到内核中的。将那些非必需的模块剔除到内核以外。 第一个是root所在的硬盘配置。 哪果您的硬盘是IDE接口,就把 ide 的选项标记下来。如果是SCSI接口,请把您的接口参数及 SCSI id 记标下来。 第二个是选择使用哪一个文件系统。 Linux的默认文件系统是是 ext2 ,那么就一定要把它标记下来。如果机器中还其它的操作系统,如win98或windows NT,您还会可能选择FAT32或NTFS的支持,不过后面你可以通过手工加载的方式来加入新的模块支持。 第三个是选择Linux所支持的可执行文件格式。这里有两种格式可供选择: elf:这是当前Linux普遍支持的可执行文件格式,必须编译到内核中 。 a.out: 这是旧版的Linux的可执行文件各函数库的格式,如果你确认肯定用不到这种格式的可执行文件,那么就可以不把它编译到内核当中。 以上这些内容,是必须要编译到内核中的。其它的内容凡是所有选项中m提示的,都选择m,这样可以通过手工的方式添加该模块。 ** Loadable module support*Enable loadable module support (CONFIG_MODULES) [Y/n/?]Set version information on all symbols for modules (CONFIG_MODVERSIONS) [N/y/?]Kernel daemon support (e.g. autoload of modules) (CONFIG_KERNELD) [Y/n/?] 分别回答 Y,N,Y 。其中 CONFIG_KERNELD 的 default 值是 N, 所以要注意选择Y。 make config 完后,仍旧是 make dep; make clean。 接下来要 make zlilo 或 make zImage。 然后 make modules ; make modules_install 。完成之后,就编译出一个没有调入多余模块的一个“干净的”内核映像文件了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值