2012年6月27日水曜日

Makefile での .PHONY と FORCE の違い

2012年6月19日火曜日

マクロを文字列化する

プリプロセッサでマクロを文字列化する方法ないかな〜、って以前から思ってたんですが、 u-boot のソースコード読んでいたときに発見しました!

どういうことかといいますと #x のような文字列化機能がプリプロセッサにありますね。
例えば、以下のような感じ。


---

#include <stdio.h>

#define MK_STR(x) #x

char buf[] = "baudrate=" MK_STR(19200);

int main()
{
    puts(buf);

    return 0;
}

---

これをコンパイル、実行すると

$ ./a.out
baudrate=19200

19200"19200" のように文字列化してくれています。ここまで普通です。


やりたいことは、19200 の部分をマクロで定義しておきたいのです。

---

#include <stdio.h>

#define CONFIG_BAUDRATE 19200
#define MK_STR(x) #x

char buf[] = "baudrate=" MK_STR(CONFIG_BAUDRATE);

int main()
{
    puts(buf);

    return 0;
}

---


$ ./a.out
baudrate=CONFIG_BAUDRATE

う〜ん、残念。
CONFIG_BUADRATE19200"19200"
と置き換えてほしいんですが、 CONFIG_BAUDRATE をそのまま文字列化してくれました。

sprintf(buf, "%d", CONFIG_BAUDRATE)
みたいに sprintf は使いたくない。

で、今回見つけたやり方は以下の方法。


---

#include <stdio.h>


#define CONFIG_BAUDRATE 19200
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)

char buf[] = "baudrate=" MK_STR(CONFIG_BAUDRATE);

int main()
{
    puts(buf);

    return 0;
}

---


$ ./a.out
baudrate=19200


おぉぉ〜!うまくいった。

一見無駄にも見える
#define XMK_STR(x) #x
#define MK_STR(x) XMK_STR(x)

というマクロ定義ですが、こんな効能があるんですね。

シェル制御文まとめ

シェル変数まとめ その2

2012年6月14日木曜日

シェル変数まとめ その1

make に無限ループ防止機能?

以下の Makefile は無限ループになるだろう、と思っているのだが、実際にやってみるとならない場合もあるみたいだ。。


$(warning restarting)
include foo.mk

all:
    echo $(BAR)

foo.mk: FORCE
    echo "BAR:=1" > $@

.PHONY: all FORCE
FORCE:


教科書的には make の動作は以下のようになります:

make は include 命令に出会うと、そのインクルードファイルを読み込みます。
ただし、インクルードファイルがなくても、エラーを報告した上で処理を続行します。
makefile を読み終わった時点で、インクルードファイルを更新するルールがないか探します。
もしルールが見つかると、通常のターゲットの更新として処理します。
ルールによりインクルードファイルが更新されると、make を最初からやりなおします。

この例の場合、
include foo.mk
がありますので、 foo.mk を構築するルールがないか探します。

foo.mk: FORCE
    echo "BAR:=1" > $@

が見つかりました。

そこで make はまず FORCE を更新し(といってもPHONYターゲットなので何もできませんが)、続いて foo.mk を更新するために
echo "BAR:=1" > $@
を実行します。

foo.mk が更新されたので、 make を最初からやりなおします。

ですが、  foo.mk: FORCE という依存関係があるので、またまた foo.mk を更新すべきと判断します。で foo.mk を更新し、また make を最初からやりなおし、といったループを繰り返すわけです。

理屈的にはこうなはずなのですが、手元の Ubuntu 11.10 マシンでやってみたら以下のようになりました。

$ make
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
echo 1
1

リスタート3回で止まった。不思議!



もう一回やってみると

$ make
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
Makefile:1: restarting
echo "BAR:=1" > foo.mk
echo 1
1

となった。

何回か同じことを繰り返すと、無限ループに入ったぞ、と判断してやめるのかな?
リスタート回数は毎回違うんですけど。。

make のバージョンは

$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
これはフリーソフトウェアです. 利用許諾についてはソースを
ご覧ください.
商業性や特定の目的への適合性の如何に関わらず, 無保証です.

This program built for x86_64-pc-linux-gnu








一方、別の RHEL マシンでやってみると、無限に繰り返すようです。
make のバージョンは同じく 3.81 です。



$ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
これはフリーソフトウェアです. 利用許諾についてはソースを
ご覧ください.
商業性や特定の目的への適合性の如何に関わらず, 無保証です.


This program built for x86_64-redhat-linux-gnu


このあたりの挙動はディストリビューションによって違うんでしょうか??
よくわかりません。

2012年6月12日火曜日

Makefile 変数のスコープ


Linux の Makefile には以下のような記述が出てきます。

clean: rm-dirs  := $(CLEAN_DIRS)
clean: rm-files := $(CLEAN_FILES)


(ターゲット): (代入文)

という記述方法ですが、これっていったいどういう機能を持つのでしょうか?


以下のような簡単な Makefile を書いて実験してみます。



foo := 1
all: bar := 1
sub: baz := 1


all: sub


all sub:
@ echo foo = $(foo) in $@
@ echo bar = $(bar) in $@
@ echo baz = $(baz) in $@


$(warning foo = $(foo) in warning)
$(warning bar = $(bar) in warning)
$(warning baz = $(baz) in warning)




$ make


を実行すると

Makefile:12: foo = 1 in warning
Makefile:13: bar =  in warning
Makefile:14: baz =  in warning
foo = 1 in sub
bar = 1 in sub
baz = 1 in sub
foo = 1 in all
bar = 1 in all
baz = in all


と表示されました。

$(warning ) 文からは barbaz の値が見えてないですし、
all の構築ルールの中では baz の値が見えてないですね。



また

$ make sub

を実行すると

Makefile:12: foo = 1 in warning
Makefile:13: bar =  in warning
Makefile:14: baz =  in warning
foo = 1 in sub
bar = in sub
baz = 1 in sub


sub の構築ルールの中では bar の値が見えないですね。


foo := 1 がグローバル変数的な振る舞いをするのに対して、

all: bar := 1 と書くと、all を構築している間だけこの代入文が見えます。
all の構築が終わると消えます。

sub: baz := 1 も同様。

ローカル変数的に使うことができますね。

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 で確認)

2012年6月9日土曜日

CodeSourcery

2012年6月8日金曜日

Gas の .align ディレクティブ

GNU Assembler の .align ディレクティブについて。

例えば、4バイトアラインするときに
.align 2 と書いている人と .align 4 と書いてる人がいて、どっちが正しいんだ?と思ったので調べてみた。

The GNU Assembler のドキュメントを参照すると、、、

The way the required alignment is specified varies from system to system.
For the a29k, hppa, m68k, m88k, w65, sparc, Xtensa, and Renesas / SuperH SH, and i386 using ELF format, the first expression is the alignment request in bytes.
For example .align 8 advances the location counter until it is a multiple of 8.
If the location counter is already a multiple of 8, no change is needed.

For other systems, including the i386 using a.out format, and the arm and strongarm, it is the number of low-order zero bits the location counter must have after advancement.
For example .align 3 advances the location counter until it a multiple of 8.
If the location counter is already a multiple of 8, no change is needed.

なんだそうだ。

例えば i386 (ELF) は
.align 2 → 2バイトアライン
.align 4 → 4バイトアライン
.align 8 → 8バイトアライン

となるのに対し、

ARMは
.align 1 → 2バイトアライン
.align 2 → 4バイトアライン
.align 3 → 8バイトアライン
となるらしい。

こりゃ気をつけな間違えるな~。

というわけで、
.balign を使えば、システムに依存せずに、

.balign 2 → 2バイトアライン
.balign 4 → 4バイトアライン
.balign 8 → 8バイトアライン

となるみたいだ。

Linux ローダブルモジュールの Makefileで


LinuxのローダブルモジュールのMakefileでよくあるサンプル。


obj-m   := foo.o


modules:
        $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules


clean:
        $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


みたいなやつ。
$(PWD) の部分は $(CURDIR) の方がいいですね。
再帰的make の中に組み込むと動かなくなってしまうので。
詳細理由は、一つ前の話題「make の -C オプションについて」で述べています。

というわけで、「Linuxデバイスドライバプログラミング」に載っているMakefileのサンプルはよくないですね。

O'REILLY の「Linuxデバイスドライバ」のサンプルの方は

PWD := $(shell pwd)

の1行が入っているのでOKです。

2012年6月7日木曜日

make の -C オプションについて

make の -C オプションについて。

man make を読むと、

-C dir
makefile を読み込むなどの動作の前に、ディレクトリ dir に移動する。
(中略) このオプションは通常、make を再帰的に呼び出すときに使われる。

と書いてあります。

ほとんどの場面で 「make -C dir」は「cd dir; make」と同じと考えていいと思うが、
わずかに挙動が違う部分があることに最近気づいた。

実験のため、次のような /home/foo/Makefile, /home/foo/bar/Makefile
という2つの Makefile を用意。

/home/foo/Makefileの内容:

all:
    @ echo CURDIR = $(CURDIR)
    @ echo PWD = $(PWD)
    @ cd bar; $(MAKE)


/home/foo/bar/Makefileの内容:

all:
    @ echo CURDIR = $(CURDIR)
    @ echo PWD = $(PWD)


/home/foo にて make を実行してみると以下のように表示された。


CURDIR = /home/foo
PWD = /home/foo
make[1]: ディレクトリ `/home/foo/bar' に入ります
CURDIR = /home/foo/bar
PWD = /home/foo/bar
make[1]: ディレクトリ `/home/foo/bar' から出ます


さて、 cd bar; $(MAKE) の部分を $(MAKE) -C bar と書き変えるとどうだろう?


/home/foo/Makefileの内容:

all:
    @ echo CURDIR = $(CURDIR)
    @ echo PWD = $(PWD)
    @ $(MAKE) -c bar ← 変更する


/home/foo/bar/Makefileの内容:

all:
    @ echo CURDIR = $(CURDIR)
    @ echo PWD = $(PWD)




実行結果は以下のようになった。

CURDIR = /home/foo
PWD = /home/foo
make[1]: ディレクトリ `/home/foo/bar' に入ります
CURDIR = /home/foo/bar
PWD = /home/foo ← 注目!!!
make[1]: ディレクトリ `/home/foo/bar' から出ます


/home/foo/bar/Makefile における $(PWD) の値が変わった。

からくりはこうだ。

CURDIR は make が提供する変数で、現在実行している make プロセスのカレントディレクトリを返す。
一方、PWD は環境変数であって、make 変数ではない。

cd bar; make」で再帰的に make を呼び出した場合、
cd bar; の時点で PWD/home/foo/bar に更新される。

一方、「make -C bar」で再帰的に make を呼び出した場合、
環境変数 PWD/home/foo を指したまま、 /home/foo/bar/Makefile に引き継がれる。


このことから、make を実行しているカレントディレクトリを指す用途には、常に $(CURDIR) もしくは $(shell pwd) を使うべきだとわかる。
$(PWD) は使うべきでない。
上の例で明らかなように、上位階層の Makefile がどのように再帰的に呼び出しているかによって  $(PWD) が返す値が変わってくるので、必ずしも期待通りに動かないからだ。

ちなみに、変数がどこからやってきているかは

$ make --print-data-base
と打ってみればわかる。

やってみると以下のように表示された。

# makefile 変数
CURDIR := /home/masahiro

(中略)

# 環境変数
PWD = /home/masahiro


さらにちなみにだが、上の例で /home/foo/bar/Makefile$(PWD) の部分を $$PWD に書き変えるとまた違う結果になる。

make の構築ルールはサブシェル上で実行されることを知っている人は多いだろう。

echo PWD = $(PWD)
については、$(PWD) を make が展開した後にサブシェルに渡しているので、サブシェルは
echo PWD = /home/foo
を実行している。

一方、
echo PWD = $$PWD
については、make が $$$ に変換してサブシェルに渡すので、サブシェルは
echo PWD = $PWD
を実行することになる。$PWD はサブシェルによって /home/foo/bar へと展開される。