前回は、LinuxのトップのMakefile の一番外のネスト
ifeq ($(skip-makefile),)
について説明しました。
その内部にさらにわかりにくい部分があります。
トップのMakefile の400行目付近からは以下のようなコードになっています。
# To make sure we do not include .config for any of the *config targets
# catch them early, and hand them over to scripts/kconfig/Makefile
# It is allowed to specify more targets when calling make, including
# mixing *config targets and build targets.
# For example 'make oldconfig all'.
# Detect when mixed targets is specified, and make a second invocation
# of make so .config is not included in this case either (for *config).
no-dot-config-targets := clean mrproper distclean \
cscope gtags TAGS tags help %docs check% coccicheck \
include/linux/version.h headers_% \
kernelversion %src-pkg
config-targets := 0
mixed-targets := 0
dot-config := 1
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
dot-config := 0
endif
endif
ifeq ($(KBUILD_EXTMOD),)
ifneq ($(filter config %config,$(MAKECMDGOALS)),)
config-targets := 1
ifneq ($(filter-out config %config,$(MAKECMDGOALS)),)
mixed-targets := 1
endif
endif
endif
Linuxのビルドにはまず、.configファイルを作らないといけません。
いきなり
$ make
とやっても .config ファイルがないよと怒られます。
普通は2回に分けて、
$ make oldconfig
$ make all
などとするところなのですが、
$ make oldconfig all
と1回でもうまくいきます。そのあたりの仕組みを説明します。
まず、makeのターゲットを3種類に分類しています。
(1) .configファイルを生成するためのターゲット (config / menuconfig / defconfig/ oldconfig など)
(2) .config がなくても実行できるターゲット (clean / mrproper / help など)
(3) .config がないと実行できないターゲット (all / vmlinux / modules など)
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
dot-config := 0
endif
endif
の部分ですが、no-dot-config-targetsには(2)の.configファイルを必要としないターゲットが列挙されています。
MAKECMDGOALS が(2) のターゲットのみからなる場合、
dot-config := 0がセットされます。(.config ファイルはなくても実行できますよ、という意味。)
それ以外の場合は dot-config := 1です。
ifeq ($(KBUILD_EXTMOD),)
ifneq ($(filter config %config,$(MAKECMDGOALS)),)
config-targets := 1
ifneq ($(filter-out config %config,$(MAKECMDGOALS)),)
mixed-targets := 1
endif
endif
endif
の部分ですが、MAKECMDGOALSが (1) .configファイルを生成するターゲットを含んでいる場合は
config-targets := 1
になります。
さらに、MAKECMDGOALSに (1)と(1)以外のターゲットが混ざっている場合は
mixed-targets := 1
になります。
dot-config, config-targets, mixed-targets の値によって、Makefileは以下のように分岐します。
ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.
%:: FORCE
$(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@
else
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target
...
config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
else
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.
...
ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf
...
# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
...
else
# Dummy target needed, because used as prerequisite
include/config/auto.conf: ;
endif # $(dot-config)
...
mixed-target が1の時は、
%:: FORCE
$(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@
の部分しか見えませんが、これは1つ1つに分けて再帰的に呼び出しています。
$ make oldconfig all
は make oldconfig と make all の2回に分けて実行されるということです。
mixed-target が0で、config-targets が1のときは
config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
の部分が、*configターゲット の生成ルールになっています。
mixed-target が0で、config-targets が0のときが、それ以降の大部分のコードになります。
dot-config が1ならば、
-include include/config/auto.conf
のようにCONFIG_設定ファイルを読み込んでいます。
.config を直接 include するのではなくて、
make silentoldconfigによって .config から include/config/auto.conf を作り、それを読み込んでいます。
dot-config が0ならば、
include/config/auto.conf は必要ないのですが、空のルールだけは、
include/config/auto.conf: ;
のように書いてあります。
include/config/auto.conf がなくてもそのまま makeは進みます。
前回に引き続き、今回もトップのMakefileのわかりにくいネストを説明しました。
インデントをつけてわかりやすくまとめますと、
ifeq ($(mixed-targets),1)
再帰的に1つずつ処理する
else
ifeq ($(config-targets),1)
.configを作る
else
ifeq ($(dot-config),1)
include/config/auto.confを読み込む
endif
本体
endif
endif
といった感じです。