Howdunnit

存在証明と生存確認

Makeの変数における代入タイプについて

変数の代入タイプ

GNU makeにおける変数の代入タイプには、:=, =, ?=, +=等があります。
その中でも、個人的によく使う以下の3つの変数についての挙動がわかり辛かったため、まとめました。

演算子 説明
:= 値を代入(即時評価)
= 値を代入(使用される度に右辺を再評価)
?= 変数が定義されていないときのみ値を代入(:=同等)

使用例から見る代入タイプ

次に、変数の代入タイプで紹介した代入タイプについて、実際に触ってみようと思います。

:= について

Makefile内で以下のように記述した場合、結果がどうなるか見ていきます。

$ cat Makefile

a := foo
b := $(a) bar
a := baz

test:
  @echo $(a)
  @echo $(b)

出力結果は以下のようになります。

$ make test
baz
foo bar

解説(又は解釈)

:=は、値を代入するものであり、即時評価するものでした。
代入時には、aにはfooが、bにはこの時点でのaの値(foo)とbarが、2回目のaには上書きする形でbazが割り当てられます。
aの出力では、2回目の代入によってbazが割り当てられている状態であるため、a = bazの状態になります。
bの出力では、bに代入されたときの状態のままであるため、b = foo barの状態になります。
よって結果は、a = baz, b = foo barとなります。

= について

Makefile内で以下のように記述した場合、結果がどうなるか見ていきます。

$ cat Makefile

a = foo
b = $(a) bar
a = baz

test:
  @echo $(a)
  @echo $(b)

出力結果は以下のようになります。

$ make test
baz
baz bar

解説(又は解釈)

=は、値を代入するものであり、使用される度に右辺を再評価するものでした。
代入時には、aにはfooが、bにはこの時点でのaの値とbarが、2回目のaには上書きする形でbazが割り当てられます。
aの出力では、2回目の代入によってbazが割り当てられている状態であるため、a = bazの状態になります。
bの出力では、:=と違って「使用される度に右辺を再評価する」という特性を持っているため、echoされる時に再評価を行います。b = $(a) bar であったため、この時点のaの状態はa = bazであることから、b = baz barの状態になります。 よって結果は、a = baz, b = baz barとなります。

?= について

Makefile内で以下のように記述した場合、結果がどうなるか見ていきます。

$ cat Makefile

a ?= foo
b ?= $(a) bar
a ?= baz

test:
  @echo $(a)
  @echo $(b)

出力結果は以下のようになります。

$ make test
foo
foo bar

解説(又は解釈)

?=は、変数に値の代入時以前に既に値が代入されている場合は代入を行わず、代入されていない場合のみ:=の役割を行うものでした。
代入時には、aにはfooが、bにはこの時点でのaの値(foo)とbarが割り当てられます。2回目のaへの代入については、既にaにfooを代入しているため、ここで代入は行われません。
aの出力では、2回目の代入では代入は行われなかったため、a = fooの状態になります。
bの出力では、bに代入されたときの状態のままであるため、b = foo barの状態になります。
よって結果は、a = foo, b = foo barとなります。

まとめ

Makefileでよく使用する3つの代入タイプについて見ていきました。 最近は仕事でも、プライベートでもMakeを使用する機会が増えているので、忘れないようにしたいと思います。