您的位置:首页 > 运维架构 > Linux

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文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: