Linux カーネルモジュールのコンパイルを行った際に何をやっているか調べてみました。
簡単なカーネルモジュール
- まず簡単なカーネルモジュールのソースコードとMakefileを用意します。
/*  
 *  hello.c - The simplest kernel module.
 */
# include <linux/module.h>   /* Needed by all modules */
# include <linux/kernel.h>   /* Needed for KERN_INFO */
int init_module(void)
{
    printk(KERN_INFO "Hello world 1.\n");
    /* 
     * A non 0 return means init_module failed; module can't be loaded. 
     */
    return 0;
}
void cleanup_module(void)
{
    printk(KERN_INFO "Goodbye world 1.\n");
}
obj-m = hello.o
all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
makeすると、どんなコマンドが実行されるか
簡単なカーネルモージュルをコンパイルするとどんなコマンドが実行されるのか。
make
をすると、カーネルソースに含まれる3つのmakefileが実行されていました。
make -C /lib/modules/3.13.0-62-generic/build M=/home/eggman/tmp/driver/kernelmodule modules
make -f scripts/Makefile.build obj=/home/eggman/tmp/driver/kernelmodule
make -f /usr/src/linux-headers-3.13.0-62-generic/scripts/Makefile.modpost
Makefile で適用されるルール
- 引数Mで指定した値をKBUILD_EXTMODに設定。
- KBUILD_EXTMODからmodule-dirsを設定
- ターゲット $(module-dirs)を生成後に、ターゲット modules を生成する。
- $(build) がどう設定されるかわかりませんが、 -f scripts/Makefile.build objが設定されてました。
ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif
module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
PHONY += $(module-dirs) modules
$(module-dirs): crmodverdir $(objtree)/Module.symvers
        $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
modules: $(module-dirs)
        @$(kecho) '  Building modules, stage 2. ';
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
scripts/Makefile.build で適用されるルール
- 
けっこう複雑でした。 
- 
.cを.oを変換するのは このルールです。 
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
        $(call cmd,force_checksrc)
        $(call if_changed_rule,cc_o_c)
- 
if_changed_ruleはscript/Kbuild.includeで定義されています。
if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
        @set -e;                                                             \
        $(rule_$(1)))
- これは rule_cc_o_c を行います。
define rule_cc_o_c
        $(call echo-cmd,checksrc) $(cmd_checksrc)                         \
        $(call echo-cmd,cc_o_c) $(cmd_cc_o_c);                            \
        $(cmd_modversions)                                                \
        $(call echo-cmd,record_mcount)                                    \
        $(cmd_record_mcount)                                              \
        scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >    \
                                                      $(dot-target).tmp;  \
        rm -f $(depfile);                                                 \
        mv -f $(dot-target).tmp $(dot-target).cmd
endef
- けっきょき cmd_cc_o_c を実行します。
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
scripts/Makefile.modpost で適用されるルール
- .koを生成します。
$(modules): %.ko :%.o %.mod.o FORCE
        $(call if_changed,ld_ko_o)```
リンカで.oを.koに変換します。
      cmd_ld_ko_o = $(LD) -r $(LDFLAGS)                                 \
                             $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
                             -o $@ $(filter-out FORCE,$^)
参考にしたページ
ずっと下書きにあったけど、公開しとく。