GNU make での条件コンパイル

twitter に垂れ流したものは流れさってしまって残らないので、拾ってまとめなおしておく。

GNU make では条件文が書ける。 たとえば変数 COND が true に設定されていたら、ソースファイルをまとめる文字列 SRCS に hoge.c を追加する、といったことを次のように書いておける。

ifeq ($(COND), true)
SRCS += hoge.c
endif

ただ、 ifeq でテストできる条件はただひとつなので、複数の条件を確認したいときにはちょっとした工夫をしないといけない。

複数の条件の論理和をとる

findstring を使って、条件変数をならべた文字列のなかに true があることを見つけることで論理和をとれる。
たとえば以下のように書けば、条件変数 A か B、 C のいずれかが true であることを検出できる。

ifeq ($(findstring true, $(A) $(B) $(C)), true)
...
endif

C 言語風に書けば "if (A || B || C)" だ。

複数条件の論理積をとる

条件変数がかならず空文字列でなく true/false のいずれかに設定されていることを前提とすれば、 filter を使って true を抽出し words を使って true の数を数える、ということで代えられる。
以下は条件変数 A、 B、 C の三つがすべて true の場合に成立する。

ifeq ($(words $(filter true, $(A) $(B) $(C))), 3)
...
endif

でも、これはちょっと …よくないなあ。 条件変数の数を数えて条件式に入れておかないといけないし、ちょっとした手違いで A が "true true true" になっていたら数え間違う。

こうしてみたらどうだろう?

COND := A B C
ifeq ($(words $(COND)), $(words $(foreach v, $(COND), $(filter true, $($(v))))))
...
endif

異様にわかりにくいけれど、テストしたい条件を COND に並べておく。 それから word 関数で条件の数を数える ($(words $(COND)))。 次に foreach 関数で COND の中にならべた条件変数をそれぞれ取り出し、 filter true で true だけを取り出す。 これの words を数えて、最初に数えておいた条件変数の数と一致すればすべての条件が true だということ。
"true true true" のような、ひとつの条件変数にいくつもの値を入れられていた場合の対策をするなら filter に与えた変数 $($(v)) を $(firstword $($(v))) に変えればよい。

けれどこれもまた複雑すぎる。 いっそ単純に、論理積ならこれでいいんじゃないか?

ifeq ($(A) $(B) $(C), true true true)
...
endif