makeでfor文

makeは非常に優秀なツールだ。 一度依存関係を書いておきさえすれば、それにしたがって勝手にコンパイルしてくれる。 しかも一つの言語ともいえるような機能を持っている。 例えば変数を持てる。Makefile中では ARG = value ARG := value の2つの代入の形式がある。 ちょっと複雑なことを使用とするとき、両者の違いは重要だ。 違いは右辺に変数が含まれるときに生じる。 前者は右辺に含まれる変数も代入された変数が評価されるときに初めて評価される。 一方後者では、代入時に右辺値が確定される。 C言語でいえば、前者は引数のない関数の定義、あるいは参照変数に近く、後者は通常の手続きにおける代入に対応する。 さらにmakeの機能にinclude文がある。 include sub.mk とすればsub.mkの中身を今読んでいるMakefileに追加したのち、コンパイルを行ってくれる。 もう一つ、makeには文字列操作に関して非常に強力な組み込みの関数がある。 今回使うのはword,words,wordlistの3つである。 これらはlistの管理を簡単にしてくれる関数である。 list = a b c d $(word 2,$(list)) # b $(words $(list)) # 4 $(wordlist 2,3,$(list)) # b c wordは所定の位置の要素を抜きだし、wordsはlistの長さを返し、wordlistは部分listをつくる。 さて、本題のfor文に取り掛かろう。 種を先にあかしておくと、再帰的にsub.mkを読み込むのである。 幸いにもinclude文は自分自身を読み込むことを拒否しないので、自己再帰的にfor文を構成する。 次のMakefileを見て欲しい。 main.mk:
TARGET = test
LIST = a b c d
all : $(TARGET)
$(TARGET) : subd
    touch $(TARGET)
include sub.mk
sub.mk:
VAR := $(word 1,$(LIST))
LIST := $(wordlist 2,$(words $(LIST)),$(LIST))
sub$(VAR):
    touch $@
ifneq ($(VAR),) # VARが空でなければ真
include sub.mk
endif
依存関係を解決するだけの簡単なMakefileだが、 制御が自己再帰的になっているので読みにくいかもしれない。 ポイントはsub.mkの2行目のLISTを一つずらすところと、 最後のsub.mkからsub.mkをincludeするところである。 LISTの先頭の値をVARに受け取り、LISTは一つ前につめる。 この変数は次のincludeのときにも引き継がれるので、 LISTが空になるまでsubdの生成方法が検索され続ける。 これによりsubdが4回目のincludeの後に発見され、めでたくtestはコンパイルされるのであった。 。。。とまぁ、for文が出来上がったのだが。 なんに使おうかな? これを調べている途中で、
LIST = a.c b.c c.c d.c
$(LIST) : %.c : %.o
    icpc $< -o $@
のような条件付きルールを書く方法を知り、当初の目的が果たせたので、 このfor文は今回必要ないのであった。