2012年6月11日月曜日

LinuxカーネルのMakefileを解析する その7


前回から間があきましたが、今回はLinux Makefile のコンパイルオプションについて解析してみた。

Makefile 中でのコンパイルオプションの与え方は Documentation/kbuild/makefiles.txt の 「3.7 Compilation flags」に記載されている。
ざっと読んでみると、

ccflags-y, asflags-y, ldflags-y
これが記載されている Makefile で有効。
(EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS も過去互換のためにサポートされているが、非推奨)

subdir-ccflags-y, subdir-asflags-y
これが記載されているMakefileとそのサブディレクトリで有効。

CFLAGS_$@, AFLAGS_$@
はファイル単位で追加したいオプションを指定する。
例) CFLAGS_foo.o := -D BAR
CPPFLAGS_$@ はないみたい。

CFLAGS_REMOVE_$@
でファイル単位で削除したいオプションを指定する。
AFLAGS_REMOVE_$@, CPPFLAGS_REMOVE_$@ はないみたい。。



このあたりのオプションがどのように実装されているか、見てみた。


コンパイルオプションはほとんど scripts/Makefile.lib の中で加工されている。
scripts/Makefile.lib は scripts/Makefile.build からインクルードされている。


まず、EXTRA_* の過去互換性のためのルールがある。

# Backward compatibility
asflags-y  += $(EXTRA_AFLAGS)
ccflags-y  += $(EXTRA_CFLAGS)
cppflags-y += $(EXTRA_CPPFLAGS)
ldflags-y  += $(EXTRA_LDFLAGS)




また、サブディレクトリにも伝搬するように、
$(subdir-asflags-y), $(subdir-ccflags-y)
KBUILD_SUBDIR_ASFLAGS, KBUILD_SUBDIR_CCFLAGS にいれて export している。


# flags that take effect in sub directories
export KBUILD_SUBDIR_ASFLAGS := $(KBUILD_SUBDIR_ASFLAGS) $(subdir-asflags-y)
export KBUILD_SUBDIR_CCFLAGS := $(KBUILD_SUBDIR_CCFLAGS) $(subdir-ccflags-y)




以下の部分で、_c_flags, _a_flags, _cpp_flags にまとめます。
KBUILD_CPPFLAGS, KBUILD_CFLAGS, KBUILD_AFLAGS は トップのMakefileとarch/*/Makefileで規定されていて、
make 全体に影響を与えます。

orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
                 $(ccflags-y) $(CFLAGS_$(basetarget).o)
_c_flags       = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
_a_flags       = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
                 $(asflags-y) $(AFLAGS_$(basetarget).o)
_cpp_flags     = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))



さらに、KBUILD_SRC が指定されている(つまり O=, M= が指定されている)ならば、インクルードパスの加工を行う。
KBUILD_SRC が指定されてなければ、 _*_flags がそのまま __*_flags になる。

ifeq ($(KBUILD_SRC),)
__c_flags = $(_c_flags)
__a_flags = $(_a_flags)
__cpp_flags     = $(_cpp_flags)
else


# -I$(obj) locates generated .h files
# $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files
#   and locates generated .h files
# FIXME: Replace both with specific CFLAGS* statements in the makefiles
__c_flags = $(call addtree,-I$(obj)) $(call flags,_c_flags)
__a_flags =                          $(call flags,_a_flags)
__cpp_flags     =                          $(call flags,_cpp_flags)
endif



これから c_flags, a_flags, cpp_flags, ld_flags が作られる。


c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
$(__c_flags) $(modkern_cflags)                           \
-D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)


a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
$(__a_flags) $(modkern_aflags)


cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
$(__cpp_flags)


ld_flags       = $(LDFLAGS) $(ldflags-y)


-Wp,-MD,$(depfile) は依存関係自動生成に使うプリプロセッサ用にオプションですね。




ようやく、これが scripts/Makefile.build のパターンルールの中で使われます。

%.c → %.o には

cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<


%.S → %.o には

cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<


%.c → %.s には

cmd_cc_s_c       = $(CC) $(c_flags) -fverbose-asm -S -o $@ $<


%.c → %.i には

cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<


%.S → %.s には
cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 


%.lds.S → %.lds には
cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
                 -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<

という風に使われるようです。



ところで、cppflags-yEXTRA_CPPFLAGS って Makefile.lib には用意されているのですが、ほとんど使われている形跡がないですね。
-Dmacro-Idir などはプリプロセッサオプションなので、cppflags-y に追加すべきと思うのですが、もっぱら ccflags-y に方に追加されているようです。



もう一つ気になるのは用語の非統一感です。

ccflags-y, EXTRA_CFLAGS, CFLAGS_$@, CFLAGS_REMOVE_$@
 → なんで cflags-y じゃなくて ccflags-y にしたの?

asflags-y, AFLAGS_$@
 → なんで ASFLAGS_$@ じゃなくて AFLAGS_$@ なの?


make でよく使われるのは CFLAGS, CPPFLAGS, ASFLAGS, LDFLAGS だと思うんですが。。(make --print-data-base で確認)

0 件のコメント:

コメントを投稿