最近在linux2.4内核上编译一个动态加载模块时遇到这样一个问题,执行make时编译器不编makefile文件中所指定的目标文件,而是提示一句 Nothing to be done for `modules',然后就退出了。
$(MAKE) -C $(KERNELPATH) SUBDIRS=$(shell pwd) modules
一、先看看执行$(MAKE) -C $(KERNELPATH) SUBDIRS=$(shell pwd) modules后脚本是怎样执行的:
modules: $(patsubst %, _mod_%, $(SUBDIRS))
这里把传入的SUBDIRS变量加上一个_mod_前缀,使modules依赖于他
$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h \ include/config/MARKER
$(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules
这里回到SUBDIRS执行modules,但是带入CFLAGS变量
2.回到SUBDIRS执行modules目标,但是Makefile文件中根本就没有这个目标的存在,当然会报Nothing to be done for `modules'了,那么这个modules目标到底是什么呢?
找个2.4与2.6内核通用的模块编译Makefile文件看看,它通常在目标all之前有这样几行语句:
-include $(TOPDIR)/Rules.make
这就是问题的关键所在!TOPDIR变量内核根Makefile文件中定义的
TOPDIR
:= $(shell /bin/pwd)
就是指内核的路径,所以Include前面的“-”就显得尤为重要。当我们敲make命令时第一次进入模块的Makefile文件,这时Rules.make文件当然找不到,但由于加了“-”所以脚本会忽略这个错误,当进入内核然后再出来时TOPDIR得到了赋值,理所当然脚本就把位于内核根目录的Rules.make文件内容插入到语句所在的位置,到这里我们就知道怎么接着分析上面的编译过程了,请接着看。
3.进入Rules.make文件,果然有modules这个目标
modules: $(ALL_MOBJS) dummy \
$(patsubst %,_modsubdir_%,$(MOD_DIRS))
它依赖于ALL_MOBJS、dummy和$(patsubst %,_modsubdir_%,$(MOD_DIRS))
ALL_MOBJS = $(filter-out $(obj-y), $(obj-m))
它过滤掉obj-m中所有和obj-y中相同的单词,保留obj-m中独有的单词,实际上就是保留了在自己的makefile文件中定义的obj-m变量,就是我们最终要生成的模块名字。所以make就会去寻找我们的obj-m目标并执行它。Modules的最后一个依赖条件仅在我们编译的模块还有别的子模块时才需要用,通常这个目标是空的。
4.进入模块自己的makefile文件,找obj-m目标,并执行。