Linux外部模块.ko建立流程
2012-08-31 00:46
591 查看
文章欢迎转载,保留联系信息,以便交流。
邮箱:eabi010@gmail.com
主页:www.ielife.cn(爱嵌论坛——嵌入式技术学习交流)
博客:blog.csdn.net/ielife
Linux内核如何支持在非源码目录下编译的模块呢?是这篇研究的方向。
一:.查看内核文档Documentation/kbuild/modules.txt
2. How to build external modules 4. Creating a kbuild file for an external module
第2章节说明编译模块所要使用的命令
make -C $KDIR M=`pwd`
make -C $KDIR M=`pwd` modules
第4章节说明如何写一个外部模块的Makefile
215 --> filename: Makefile 216 ifneq ($(KERNELRELEASE),) 217 # kbuild part of makefile 218 obj-m := mydrivers.o 220 221 else 222 # Normal Makefile 224 KERNELDIR := /lib/modules/`uname -r`/build 225 all:: 226 $(MAKE) -C $(KERNELDIR) M=`pwd` 232 endif
以上的Makefile与驱动代码mydrivers.c放在同一目录下,执行make即可
其中,make时先执行else中的双冒号目标all,执行命令make -C $(KERNELDIR) M=`pwd`
make -C $(KERNELDIR)表示切换到$(KERNELDIR)目录下执行Makefile文件,因此$(KERNELDIR)需要指定你的源代码树的根目录,根据自己的情况修改224行
而ifneq中的obj-m会在源码树的执行中再次被读取
二:跟踪Makefile的执行流程
由于已经make -C到Linux内核Makefile中,因此分析内核源码目录下的Makefile文件,首先传递进来的M=`pwd`,使得Makefile中会执行
72 ifdef M 73 ifeq ("$(origin M)", "command line") 74 KBUILD_EXTMOD := $(M) 75 endif 76 endif
KBUILD_EXTMOD变量会因为make时传递进来的M而被赋值为外部模块所在的目录
KBUILD_EXTMOD不为空,会自动加上modules选项
137 ifeq ($(KBUILD_EXTMOD),) 138 _all: all 139 else 140 _all: modules 141 endif
因此会执行modules目标
三:modules目标
内核中有两种编译modules的方法,所以有两个地方有modules的目标规则,一个是基于源码树编译的modules,一个是基于外部编译模块使用的modules
区分两者主要是KBUILD_EXTMOD变量,看Makefile中的内容
559 ifeq ($(KBUILD_EXTMOD),) ...... 958 PHONY += modules 959 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) 960 @echo ' Building modules, stage 2.'; 961 $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost ...... 1165 else ...... 1185 KBUILD_MODULES := 1 1186 PHONY += crmodverdir 1187 crmodverdir: 1188 $(Q)mkdir -p $(MODVERDIR) 1189 $(Q)rm -f $(MODVERDIR)/* 1190 1191 PHONY += $(objtree)/Module.symvers 1192 $(objtree)/Module.symvers: 1193 @test -e $(objtree)/Module.symvers || ( \ 1194 echo; \ 1195 echo " WARNING: Symbol version dump $(objtree)/Module.symvers"; \ 1196 echo " is missing; modules will have no dependencies and modversions ."; \ 1197 echo ) 1198 1199 module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD)) 1200 PHONY += $(module-dirs) modules 1201 $(module-dirs): crmodverdir $(objtree)/Module.symvers 1202 $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) 1203 1204 modules: $(module-dirs) 1205 @echo ' Building modules, stage 2.'; 1206 $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost由于KBUILD_EXTMOD不为空,所以执行1165行的else。在1204行会看到外部模块modules的目标规则,会发现modules的建立需要两个stage
stage1主要完成mydrivers.o,stage2通过Makefile.modpost脚本实现.o文件到.ko文件的转化
四:stage1编译过程
crmodverdir 创建$(MODVERDIR)变量所定义的目录,以下为变量定义处
339 export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
Module.symvers包含所有被内核构建所导出的符号。
根据以上1185~1202可知道,.o文件是由命令$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
其中build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj,及build = -f $(srctree)/scripts/Makefile.build obj=$(KBUILD_EXTMOD)
即是传递过来的M=所指定的路径,scripts/Makefile.build文件是Linux内核执行命令的接口文件,而顶层的Makefile一般不执行命令。
由于是make -f scripts/Makefile.build会把后面的文件当作Makefile来解析,因此需要查看Makefile.build文件中的内容
83 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ 84 $(if $(KBUILD_MODULES),$(obj-m)) \ 85 $(subdir-ym) $(always) 86 @:其中,只有obj-m变量被赋值,因为我们外部写的模块会给出obj-m所对应要编译的选项名字
通过script/Makefile.lib的解析,会执行以下部分(静态模式匹配):
200 # Built-in and composite module parts 201 $(obj)/%.o: $(src)/%.c FORCE 202 $(call cmd,force_checksrc) 203 $(call if_changed_rule,cc_o_c) 204 205 # Single-part modules are special since we need to mark them in $(MODVERDIR) 206 207 $(single-used-m): $(obj)/%.o: $(src)/%.c FORCE 208 $(call cmd,force_checksrc) 209 $(call if_changed_rule,cc_o_c) 210 @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)这样就生成了.o文件,其中的变量定义都来自于script/Makefile.lib中,例如if_changed_rule就是其中定义的,
call函数会调用cmd_cc_o_c生成mydrivers.o文件,当然在210行还会生成相应的mod.c文件
第二个阶段需要Module.symvers,mod.c和stage1阶段的.o文件来生成最终的.ko文件
五:stage2编译过程
模块的第二次编译来自modules规则中的$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
Makefile.modpost是通过.o生成.ko文件的工具
以上并没有把分析过程的细节,包括Makefile中的语法,及依赖的展开和包含的头文件中定义的相关重要变量和内容做说明,仅是以流程为主,
这些语法在make手册中都会有,其实只要明白了make的语法,顺藤摸瓜就知道外部模块构建的过程了
总结就是,先通过内核的Doc来编写一个外部的Makefile
其次明白内核Makefile的结构,顶层Makefile是确定执行的目标类型
Makefile.build才是真正建立规则的入口,而其中使用到的判断逻辑和值的定义来自Makefile.include和Makefile.lib
最终执行Makefile.modpost编译.o为.ko文件
相关文章推荐
- 有方M660模块建立TCP详细流程
- 拜师鸟哥之linux学习体会(15)——开机流程、模块管理与Loader
- 模块化建立项目流程(Maven聚合模块)
- Linux 模块(ko)签名
- Linux下hello.ko内核模块制作的全过程
- ltib添加编译linux外部模块
- Day7:Linux的启动流程、模块管理和Loader
- 模块化建立项目流程(Maven聚合模块)
- Linux的启动流程、模块管理与boot Loader
- 内核模块的自动加载和Ubuntu-Linux的开机流程(ubuntu6.10~ubuntu9.10)
- linux 内核模块ko入门
- Linux最小根文件系统的建立,内核模块的编译,Qemu模拟测试最小系统
- 在Ubuntu上为Android系统编写Linux内核驱动程序 + 编写加载动态模块ko
- 让 Linux 启动时加载自己的驱动模块 .ko
- 如何编译linux第一个模块 hellomod.ko
- 内核模块的自动加载和Ubuntu-Linux的开机流程(ubuntu9.10到现在的ubuntu发行版)
- Linux下hello.ko内核模块制作的全过程
- Linux可插拔认证模块(PAM)的配置文件、工作原理与流程
- linux开机流程、模块管理与Loader(续)
- linux、内核源码、内核编译与配置、内核模块开发、内核启动流程