make で for ループを回したい

子make というか、サブmake というか、入れ子で複数の target を make するのに、Makfile 中で for で ループを回したいなぁと思ったら、色々はまりながらも試行錯誤したらうまく行ったので、その時のメモ。

; と && の違い

Makefile 中の for ループの各ステートメントを ; で結ぶと、失敗しても(戻り値が0でなくても)先へ進んでしまうようです:

***/make $ cat Makefile
TARGETS := a b c
 
hoge:
        @for target in $(TARGETS); do\
                make aaa; \
                make bbb; \
        done
        make ccc
 
bbb:
        echo "bbb"
 
ccc:
        echo "ccc"
***/make $ make
make[1]: ディレクトリ `/***/make' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make' から出ます
make[1]: ディレクトリ `/***/make' に入ります
echo "bbb"
bbb
make[1]: ディレクトリ `/***/make' から出ます
make[1]: ディレクトリ `/***/make' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make' から出ます
make[1]: ディレクトリ `/***/make' に入ります
echo "bbb"
bbb
make[1]: ディレクトリ `/***/make' から出ます
make[1]: ディレクトリ `/***/make' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make' から出ます
make[1]: ディレクトリ `/***/make' に入ります
echo "bbb"
bbb
make[1]: ディレクトリ `/***/make' から出ます
make ccc
make[1]: ディレクトリ `/***/make' に入ります
echo "ccc"
ccc
make[1]: ディレクトリ `/***/make' から出ます
***/make $

; の代わりに && を使うと、ステートメントが失敗(戻り値が 0 以外)したら、ループの先頭に戻ります。continue 相当って感じですかね:

***/make $ cat Makefile
TARGETS := a b c

hoge:
@for target in $(TARGETS); do\
make aaa && \
make bbb; \
done
make ccc

bbb:
echo "bbb"

ccc:
echo "ccc"
***/make $ make hoge
make[1]: ディレクトリ `/***/make' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make' から出ます
make[1]: ディレクトリ `/***/make' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make' から出ます
make[1]: ディレクトリ `/***/make' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make' から出ます
make: *** [hoge] エラー 2
***/make $
 でも結局これだと、for ループ自体は止まりません。

 

for ループ中で make が失敗したら、その時点でループも抜けたい
というわけで、次は for ループ中の各ステートメントが失敗したら(戻り値が 0 以外)、その時点でループも抜ける方法です:
***/make/for2 $ cat Makefile
TARGETS := a b c

hoge:
        @for target in $(TARGETS); do\
                make aaa || exit 50; \
                make bbb; \
        done
        make ccc

bbb:
        echo "bbb"

ccc:
        echo "ccc"
$ make
make[1]: ディレクトリ `/***/make/for2' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make/for2' から出ます
make: *** [hoge] エラー 50
***/make/for2 $

|| を使うと、直前の make が失敗したら || 以降を実行してくれます。そこで exit 50; としてるわけです。なお、50 にしたのは見た目がわかりやすいかなー位で、数値自体に意味はないス。

 

for ループの中でかっこ () も使いたい

make の中でかっこ()を使うと、cd とかの影響範囲を限定できます。

例えば、サブディレクトリ名を for ループで回して、各サブディレクトリに入って make とかしたいなーという場合には、こんな感じで書けます(このサンプルでは、サブディレクトリの Makefile は echo してるだけです):

***/make/for$ tree
.
├── a
│   └── Makefile
├── b
│   └── Makefile
├── c
│   └── Makefile
└── Makefile

3 directories, 4 files
***/make/for$ cat Makefile
TARGETS := a b c

all:
        @for target in $(TARGETS); do \
        ( \
                cd $$target; \
                make; \
        ) \
        done
***/make/for$ make
make[1]: Entering directory `/***/make/for/a'
echo "aaa"
aaa
make[1]: Leaving directory `/***/make/for/a'
make[1]: Entering directory `/***/make/for/b'
echo "bbb"
bbb
make[1]: Leaving directory `/***/make/for/b'
make[1]: Entering directory `/***/make/for/c'
echo "ccc"
ccc
make[1]: Leaving directory `/***/make/for/c'
***/make/for$

かっこ()内で cd すると、かっこを抜けた時にカレントディレクトリが元に戻ります。

そんな for ループも、失敗したらその時点で make 全体止まってほしいなぁと思って、上と同じように、こんな感じで書いてみました:

***/make/for3$ cat Makefile
TARGETS := a b c

hoge:
        @for target in $(TARGETS); do\
        ( \
                make aaa || exit 50; \
                make bbb; \
        ) \
        done
        make ccc

bbb:
        echo "bbb"

ccc:
        echo "ccc"
***/make/for3$ make
make[1]: ディレクトリ `/***/make/for3' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make/for3' から出ます
make[1]: ディレクトリ `/***/make/for3' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make/for3' から出ます
make[1]: ディレクトリ `/***/make/for3' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make/for3' から出ます
make: *** [hoge] エラー 50
***/make/for3$

うーん、かっこ()をつけたら、また for ループが止まらなくなってしまいました。というわけで、かっこ()に対してもさらに || exit をつけたら、期待した通りの動きになりました:

***/make/for3$ cat Makefile
TARGETS := a b c

hoge:
        @for target in $(TARGETS); do\
        ( \
                make aaa || exit 50; \
                make bbb; \
        ) || exit 70; \
        done
        make ccc

bbb:
        echo "bbb"

ccc:
        echo "ccc"
***/make/for3$ make
make[1]: ディレクトリ `/***/make/for3' に入ります
make[1]: *** ターゲット `aaa' を make するルールがありません.  中止.
make[1]: ディレクトリ `/***/make/for3' から出ます
make: *** [hoge] エラー 70
***/make/for3$

例によって、exit の 50 とか 70 とかは深い意味なしです。


コメントを残す

メールアドレスが公開されることはありません。