2014年12月26日金曜日
2014年10月24日金曜日
2014年7月15日火曜日
2014年6月5日木曜日
2014年5月28日水曜日
2014年5月27日火曜日
2014年5月13日火曜日
2014年2月7日金曜日
2014年1月21日火曜日
2013年10月29日火曜日
2012年10月10日水曜日
LinuxカーネルのMakefileを解析する その8
前回からまたまた間があきました。
今回の話題は O= を付けた時の動作についてです。
ソースを見ていて、あれっ、どうやって動いてるんだっけ?という部分がありましたので記載しておきます。
例えば、Kernel のソースツリーで
$ make O=dir/to/store/output/files/ defconfig vmlinux
とやってみると、
ソースツリーを一切汚すことなく、
dir/to/store/output/files/ に出力結果を置いてくれます。
トップの Makefile の動きは 「LinuxカーネルのMakefileを解析する その1」で解説しました。
今回注目するのは script/Makefile.build です。
例えば、*.c から *.o を生成するサフィックスルールを見てみます。
Makefile.build の300行目過ぎにそれがあります。
今回の話題は O= を付けた時の動作についてです。
ソースを見ていて、あれっ、どうやって動いてるんだっけ?という部分がありましたので記載しておきます。
例えば、Kernel のソースツリーで
$ make O=dir/to/store/output/files/ defconfig vmlinux
とやってみると、
ソースツリーを一切汚すことなく、
dir/to/store/output/files/ に出力結果を置いてくれます。
トップの Makefile の動きは 「LinuxカーネルのMakefileを解析する その1」で解説しました。
今回注目するのは script/Makefile.build です。
例えば、*.c から *.o を生成するサフィックスルールを見てみます。
Makefile.build の300行目過ぎにそれがあります。
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
これは $(src)/%.c から $(obj)/%.o を生成してくれるルールを表しています。
Makefile.build の先頭に
src := $(obj)
がありますので、src と obj は同じディレクトリを指しています。
O= 指定がないときは、それでいいのですが、O= 指定ありの時は、 *.c と違うディレクトリに *.o を作りたいわけです。
obj と src が同じなのに、どうやって動いてるんだろう??としばらく悩みましたが、その答えはトップの Makefile の 150行目過ぎにある
VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))
export srctree objtree VPATH
にあります。
VPATHに $(srctree) が追加されています。
VPATHというのは、make がサフィックスルールにおいて検索するパスを指定するものです。
Cコンパイラでいうところの -I オプションみたいなものといういえばいいでしょうか。
$(obj)/*.o を生成するときに、 $(src)/*.c を探しますが、見つかりません。
次にVPATHで指定されたパスを探しにいき、$(srctree)/$(src)/*.c を使うわけです。
VPATHというのは、私は使わない方がいいと思っている機能なので(どのファイルをコンパイルしているかわかりにくくなる)、うっかり失念しておりました。
2012年8月1日水曜日
Linux ライクな autoconf.h を簡単に作る
Linux の Makefile においては、.config ファイルの内容から
include/config/auto.conf
と
include/generated/autoconf.h
が作られる。
前者はすべての Makefile から include され、
後者は -include include/generated/autoconf.h としてすべてのCのソースに渡される。
Makefile でも Cのソースでも、同じ設定内容を参照できるようにするというアイデアは素晴らしいと思う。
自前のソフトでも同様のことをしたいが、Linux の scripts/kconfig/conf を使うほどでもないという場合、以下のように make の簡単なコードでほぼ同等のことをできる。
Makefile の実装例:
include .config
auto.conf: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo $v='$($v)';))) > $@
autoconf.h: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo \#define $v $(if $(filter y,$($v)),1,'$($v)');))) > $@
include/config/auto.conf
と
include/generated/autoconf.h
が作られる。
前者はすべての Makefile から include され、
後者は -include include/generated/autoconf.h としてすべてのCのソースに渡される。
Makefile でも Cのソースでも、同じ設定内容を参照できるようにするというアイデアは素晴らしいと思う。
自前のソフトでも同様のことをしたいが、Linux の scripts/kconfig/conf を使うほどでもないという場合、以下のように make の簡単なコードでほぼ同等のことをできる。
Makefile の実装例:
include .config
auto.conf: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo $v='$($v)';))) > $@
autoconf.h: .config
@ ($(foreach v, $(filter CONFIG_%, $(.VARIABLES)), \
$(if $($v), echo \#define $v $(if $(filter y,$($v)),1,'$($v)');))) > $@
例えば、
CONFIG_FOO=y
CONFIG_BAR="abcdef"
CONFIG_BUZ=0x100
# CONFIG_QUX is not set.
という内容の .config を食わせてみる。
実行結果は以下の通り。
$ make auto.conf
$ make autoconf.h
$ cat auto.conf
CONFIG_FOO=y
CONFIG_BUZ=0x100
CONFIG_BAR="abcdef"
$ cat autoconf.h
#define CONFIG_FOO 1
#define CONFIG_BUZ 0x100
#define CONFIG_BAR "abcdef"
sed などで、 .config を parse してもよいのだが、make の .VARIABLES に定義済み変数が全部入っているので、そこから CONFIG_ で始まるものを抽出すれば簡単である。
.config 中で =y のものは、 autoconf.h では 1 に define される。
本家 Linux では =m のものは autoconf.h の方では (変数名)_MODULE が定義されるが、今回のサンプルには実装していない。
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-y や EXTRA_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 で確認)
登録:
投稿 (Atom)