红联Linux门户
Linux帮助

linux编译模块make -C path_to_kernel_src M=`pwd` modules的理

发布时间:2016-02-23 10:28:02来源:linux网站作者:Yuri800

这篇文章侧重点在M=`pwd`的个人理解,不足之处希望大神斧正,谢谢。


一直以为M=`pwd`是make的参数,可是这个参数也写的够简单。最近重看<跟我写makefile>时,发现常有这样的makefile内容:

# Use 'make V=1' to see the full commands 
ifdef V 
ifeq ("$(origin V)", "command line") 
KBUILD_VERBOSE = $(V) 
endif 
endif 


出于好奇,make时顺手输入make V=1,接下来就是被整屛的编译信息包围。在makefile中,ifdef/endif用于判断变量是否定义,而origin函数则告诉make,这个变量是来自命令行输入还是文件中定义。那么,整句话被理解为:如果定义了变量V,并且V来自于命令行,那么编译时将输出详细信息。

由此,想到编译模块时,也会传入M=`pwd`,虽然网上清一色的解释,这是指定模块路径的参数,但总觉得有失严谨(当然,这篇文章也未必严谨)。百度了诺干页,终于整理出了我想要的答案:


在内核makefile中有如下一段(网摘,暂未考证,不过可信度很高)

# Use make M=dir to specify directory of external module to build 
# Old syntax make ... SUBDIRS=$PWD is still supported 
# Setting the environment variable KBUILD_EXTMOD take precedence 
ifdef SUBDIRS 
KBUILD_EXTMOD ?= $(SUBDIRS) 
endif 
 
ifeq ("$(origin M)", "command line") 
KBUILD_EXTMOD := $(M) 
endif 


从这段内容理解如果make传入的命令行变量存在且是M,那么,变量KBUILD_EXTMOD变为变量M的值,即`pwd`。

从变量名可推知,这极有可能是编译外部模块相关的变量,以此为字眼继续搜索。网上有人列举编译内核时涉及的环境变量时提到:

KBUILD_EXTMOD:当编译外部模块时设置内核源码查找路径,目录可以用以下几种方式指定 
1、在命令行用M=path 
2、环境变量KBUILD_EXTMOD 
3、环境变量SUBDIRS 
用M=path会覆盖其它两种情况 


从这至少可以确定,我的猜测还算靠谱,但是还是没有找到如何将代码编译成模块。那就继续搜索,最终在一篇名为<Linux Kbuild工作原理详细分析(以DVSDK生成PowerVR显卡模块为例)>(http://www.csdn123.com/html/blogs/20130709/33930.htm)文章中找到相关线索。

按作者原文,编译模块分2个阶段(其实这个在ldd上也提到,反正我一直不理解):step 1:编译生成mod.o文件;step 2:好像涉及到模块链接和生成sym信息。2.6以后的内核编译完模块后都会为模块链接生成符号信息,其中涉及到Makefile.modpost,关于这个的作用可以参考存在依赖关系的内核模块的编译问题(http://blog.chinaunix.net/uid-23769728-id-3792911.html)。看过这篇文章,再结合kbuild在根目录下寻找目标modules的代码:

PHONY += modules 
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) 
$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) >  

$(objtree)/modules.order 
@$(kecho) '  Building modules, stage 2.'; 
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost 
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild 


最后第二句是make -f Makefile.modpost,用这种非标准名字的makefile文件执行代码编译,而scripts/Makefile.modpost中这句:

include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \ 
$(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile) 

意思是如果在KBUILD_EXTMOD路径下找到Kbuild就include $(KBUILD_EXTMOD)/Kbuild,否则include $(KBUILD_EXTMOD)/Makefile。这个路径正好包括我们自己的代码路径,因此,模块顺利的被编译链接。


本文永久更新地址:http://www.linuxdiyf.com/linux/18309.html