第340回では、2つの引数を取る条件ディレクティブ「ifeq」を取り上げた。2つの引数が等しいときに「真」となる条件ディレクティブで、プラットフォームの違いなどで動作を変えるなどの用途で使われる。今回はこの条件ディレクティブの逆となる「ifneq」を紹介する。

条件ディレクティブ ifneq

ifneqは、ifeqと逆の動きをする。機能としては「ifeq else」の「else」の前後が逆になるようなものなので、ifneqを使わないで全てifeqで書くこともできる。そのため、覚えるのが面倒ならifeqだけ覚えておけばよいとも言えるが、ifneqの方がわかりやすく書けることもあるので、覚えておいて損はないと思う。

書き方もifeqとほとんど同じだ。次のような書き方ができる。

◆ifneqディレクティブの書き方サンプル1

ifneq (引数1,引数2)

◆ifneqディレクティブの書き方サンプル2

ifneq '引数1' '引数2'

◆ifneqディレクティブの書き方サンプル3

ifneq "引数1" "引数2"

◆ifneqディレクティブの書き方サンプル4

ifneq "引数1" '引数2'

◆ifneqディレクティブの書き方サンプル5

ifneq '引数1' "引数2"

真偽値が逆になるだけで、使い方はifeqとまったく同じだ。次に実際のサンプルを見ながら動きを見ていこう。

ifneqの使い方サンプル

まず、次のMakefileを見てみよう。ifneqで比較を行っている。ifneqの条件は全て等しくなるように書いてあるので、条件は全て「偽」と評価され、else以降の処理が行われることになる。

ifneq ("a","a")
val1:=  a
else
val1:=  A
endif

ifneq 'b' 'b'
val2:=  b
else
val2:=  B
endif

ifneq "c" "c"
val3:=  c
else
val3:=  C
endif

ifneq "d" 'd'
val4:=  d
else
val4:=  D
endif

ifneq 'e' "e"
val5:=  e
else
val5:=  E
endif

test:
    @echo $(val1)
    @echo $(val2)
    @echo $(val3)
    @echo $(val4)
    @echo $(val5)

実行すると次のようになる。条件が全て「偽」なので、elseの次の行が評価されていることを確認できる。

% make
A
B
C
D
E
% 

今度は真逆のサンプルを見てみよう。ifneqの引数を全て異なるものになるようにしてあるので、条件は全て「真」となり、elseの前の式が評価されるはずだ。

ifneq ("a","A")
val1:=  a
else
val1:=  A
endif

ifneq 'b' 'B'
val2:=  b
else
val2:=  B
endif

ifneq "c" "C"
val3:=  c
else
val3:=  C
endif

ifneq "d" 'D'
val4:=  d
else
val4:=  D
endif

ifneq 'e' "E"
val5:=  e
else
val5:=  E
endif

test:
    @echo $(val1)
    @echo $(val2)
    @echo $(val3)
    @echo $(val4)
    @echo $(val5)

実行すると次のようになる。

% make
a
b
c
d
e
% 

先ほどのMakefileとは逆に、今度はelseの前の式が評価されていることがわかる。

ifeqとifneqは書ける場所も同じだ。前述したようにレシピではないところに書くことができるし、次のようにレシピに挟むようにして書いていくこともできる。

test:
ifneq ("a","a")
    @echo a
else
    @echo A
endif
ifneq 'b' 'b'
    @echo b
else
    @echo B
endif
ifneq "c" "c"
    @echo c
else
    @echo C
endif
ifneq "d" 'd'
    @echo d
else
    @echo D
endif
ifneq 'e' "e"
    @echo e
else
    @echo E
endif

実行すると次のようになる。

% make
A
B
C
D
E
% 

先ほどと同じように条件の評価が逆にないようにしつつ、レシピ部分に挟むように書くと次のようになる。

test:
ifneq ("a","A")
    @echo a
else
    @echo A
endif
ifneq 'b' 'B'
    @echo b
else
    @echo B
endif
ifneq "c" "C"
    @echo c
else
    @echo C
endif
ifneq "d" 'D'
    @echo d
else
    @echo D
endif
ifneq 'e' "E"
    @echo e
else
    @echo E
endif

実行結果は以下の通りだ。

% make
a
b
c
d
e
% 

ifneqもifeqのように「else ifneq」といった使い方ができる。これまで個別に「ifneq-else」を使ってきたが、「ifneq-else ifneq-else ifneq- ... else-endif」のように連続して書くこともできる。次のようになる。

ifneq "a" "a"
val:=   a
else ifneq "b" "b"
val:=   b
else ifneq "c" "c"
val:=   c
else ifneq "d" "d"
val:=   d
else ifneq "e" "E"
val:=   e
else
val:=   f   
endif

test:
    @echo $(val)

実行すると次のようになる。

% make
e
% 
  • 実行サンプル

    実行サンプル

これも条件を変えて書いてみると次のようになる。

ifneq "a" "a"
val:=   a
else ifneq "b" "b"
val:=   b
else ifneq "c" "c"
val:=   c
else ifneq "d" "d"
val:=   d
else ifneq "e" "e"
val:=   e
else
val:=   f   
endif

test:
    @echo $(val)

実行結果は次の通りだ。

% make
f
% 

条件ディレクティブifeqとifneqは式の評価が異なるだけで、ほかは全て同じだ。この2つの条件ディレクティブは一緒に覚えてしまおう。

条件ディレクティブとシェルのifの使い分け

条件ディレクティブはレシピでもレシピ以外でも使うことができるMakefileの機能だ。しかし、条件ディレクティブは多用するとMakefileが見にくくなっていくので、できるだけシンプルになるようにしておいた方がよいと思う。

また、レシピにおいてはMakefileの条件ディレクティブifeqやifneqを使わなくても、シェルのifや[、test、||、&&など、条件処理を行う機能はいくつも使うことができる。どちらを使うかはケースバイケースなのだが、「レシピにおいては条件ディレクティブのifeqとifneqは使わないでシェルの条件機能を使う」「それ以外の場所ではifeqまたはifneq条件ディレクティブを使う」というのは一つの指針にはなるのではないだろうか。

機能があるからといって全て使えばよいというものではないのだ。目的は仕事を効率良く進めることにある。それには、Makefileは読みやすくわかりやすくしておくことが好ましい。機能は機能として知っておいて、適材適所で使うようにしていこう。

参考