这篇文章侧重点在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显卡模块为例)>文章中找到相关线索。
按作者原文,编译模块分2个阶段(其实这个在ldd上也提到,反正我一直不理解):step 1:编译生成mod.o文件;step 2:好像涉及到模块链接和生成sym信息。2.6以后的内核编译完模块后都会为模块链接生成符号信息,其中涉及到Makefile.modpost,关于这个的作用可以参考存在依赖关系的内核模块的编译问题 。看过这篇文章,再结合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。这个路径正好包括我们自己的代码路径,因此,模块顺利的被编译链接。