GNU Makefile変数割り当て=、?=、:=、+ =の違いは何ですか?


765

Makefileで変数の割り当てが実際にどのように機能するかについて、誰でも明確に説明できますか?

違いは何ですか :

 VARIABLE = value
 VARIABLE ?= value
 VARIABLE := value
 VARIABLE += value

私はGNU Makeのマニュアルのセクションを読みましたが、それでも私には意味がありません。

回答:


1029

レイジーセット

VARIABLE = value

変数の通常の設定ですが、valueフィールドで言及された他の変数は、宣言されたときのものではなく、変数が使用された時点での値で再帰的に展開されます

即時セット

VARIABLE := value

内部の値の単純な展開による変数の設定-その中の値は宣言時に展開されます。

不在の場合は遅延セット

VARIABLE ?= value

値がない場合のみの変数の設定。valueVARIABLEアクセスすると、常に評価されます。に相当

ifeq ($(origin FOO), undefined)
  FOO = bar
endif

詳細については、ドキュメントを参照してください。

追加

VARIABLE += value

指定された値を既存の値に追加する(または、変数が存在しない場合はその値に設定する)


25
A + = BはBを拡張しますか?つまり、A + = Bを実行し、次にB + = Cを実行した場合、Aは$ {B}と$ {C}の連結と評価されますか?
アントンダネイコ2013

15
マニュアルのリンクされたセクションが言うように。+ =は、元の割り当てが持っていた単純または再帰的なセマンティクスに従って動作します。したがって、そうです、それはRHSを拡張しますが、それをすぐに行うか、遅延方法で行うかは、LHSの変数のタイプに依存します。
Etan Reisner 2013

6
変数値が展開されているとはどういう意味ですか?
Sashko Lykhenko、2015

3
@СашкоЛихенкоを見て、拡張の意味を 理解してくださいgnu.org/software/make/manual/make.html#Flavors
Umair R

7
「不在の場合に設定」は遅延または即時ですか?「不在の場合はレイジーセット」と「absetの場合はイミディエイトセット」を使用できますか
Woodrow Barlow

268

を使用する=と、変数に値が割り当てられます。変数にすでに値がある場合は、置き換えられます。この値は使用時に拡張されます。例えば:

HELLO = world
HELLO_WORLD = $(HELLO) world!

# This echoes "world world!"
echo $(HELLO_WORLD)

HELLO = hello

# This echoes "hello world!"
echo $(HELLO_WORLD)

の使用:=はの使用に似てい=ます。ただし、値は使用時に展開されるのではなく、割り当て中に展開されます。例えば:

HELLO = world
HELLO_WORLD := $(HELLO) world!

# This echoes "world world!"
echo $(HELLO_WORLD)

HELLO = hello

# Still echoes "world world!"
echo $(HELLO_WORLD)

HELLO_WORLD := $(HELLO) world!

# This echoes "hello world!"
echo $(HELLO_WORLD)

を使用すると?=、以前に変数が割り当てられていなかった場合に、変数に値が割り当てられます。変数に以前に空白値(VAR=)が割り当てられていた場合、それはまだセット見なされます。それ以外の場合、機能はまったく同じです=

using +=はusing =に似ていますが、値を置き換えるのではなく、値を現在の値にスペースを入れて追加します。変数が以前にで設定されていた場合、:=展開されると思います。結果として得られる値は、使用すると拡張されると思います。例えば:

HELLO_WORLD = hello
HELLO_WORLD += world!

# This echoes "hello world!"
echo $(HELLO_WORLD)

のようなものHELLO_WORLD = $(HELLO_WORLD) world!が使用された場合、再帰が発生し、Makefileの実行が終了する可能性が高くなります。場合A := $(A) $(B)に使用された、その結果は、使用するのとまったく同じではない+=ので、Bで展開されている:=のに対し+=起こさないB拡張します。


3
その結果はそれゆえであるVARIABLE = literalVARIABLE := literal常に同じです。私はそれを正しく理解しましたか?
aiao 2014年

1
リテラルは、その用途に不変であるとはい、@aiao
セバスチャン

微妙な違いは次のとおりです:-?:再帰呼び出しと呼ばれるメイクファイルのパフォーマンスを改善できます。たとえば$の場合 = $(shell some_command_that_runs_long_time)。再帰呼び出しでは、これは一度だけ評価されます。ビルドのパフォーマンスを向上させます。:=コマンドは不必要に複数回実行されるため、遅くなります
KeshV

61

「make」を使用していくつかの実験を行うことをお勧めします。これは、=との違いを示す簡単なデモ:=です。

/* Filename: Makefile*/
x := foo
y := $(x) bar
x := later

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

test:
    @echo x - $(x)
    @echo y - $(y)
    @echo a - $(a)
    @echo b - $(b)

make test プリント:

x - later
y - foo bar
a - later
b - later bar

詳細な説明はこちらで確認してください


5
@この混乱する結果の繰り返しを避けるために、各レシピの前にaを使用することをお勧めします。
Alexandro de Oliveira 2017年

2
Makeは/* ... */ブロックコメントをサポートしていません
yoonghm '12 / 08/19

31

を使用するVARIABLE = value場合、valueが実際に別の変数への参照である場合、値はVARIABLEが使用されるときにのみ決定されます。これは例で最もよく説明されています:

VAL = foo
VARIABLE = $(VAL)
VAL = bar

# VARIABLE and VAL will both evaluate to "bar"

を使用するとVARIABLE := valuevalue 現在の値が得られます。例えば:

VAL = foo
VARIABLE := $(VAL)
VAL = bar

# VAL will evaluate to "bar", but VARIABLE will evaluate to "foo"

を使用VARIABLE ?= valすると、VARIABLE if の値のみが設定されますVARIABLE。まだ設定されていない場合、値の設定はVARIABLEが使用されるまで延期されます(例1のように)。

VARIABLE += valueに追加valueするだけVARIABLEです。の実際の値はvalue=またはを使用して、最初に設定されたときと同じように決定されます:=


実際、最初の例では、VARIABLEは$(VAL)で、VALはbarです。VARIABLEは使用時に展開されます。
ストレッジャー2009年

1
はい、コメントはそれらが使用されたときに何が起こるかを説明しています。
ミパディ2009年

ああ。あなたはそれを修正したと思います、または私は「評価」を「ある」と誤解しています。
ストレッジャー、2009年

7

上記の回答では、「値は宣言/使用時に展開される」とはどういう意味かを理解することが重要です。のような値を指定*.cしても、拡張は必要ありません。この文字列がコマンドによって使用された場合のみ、何らかのグロビングがトリガーされる可能性があります。同様に、拡張のような値$(wildcard *.c)または$(shell ls *.c)拡張を伴わない値は、使用した場合でも定義時に完全に評価されます:=、変数定義でしたます。

Cファイルがあるディレクトリで次のMakefileを試してください。

VAR1 = *.c
VAR2 := *.c
VAR3 = $(wildcard *.c)
VAR4 := $(wildcard *.c)
VAR5 = $(shell ls *.c)
VAR6 := $(shell ls *.c)

all :
    touch foo.c
    @echo "now VAR1 = \"$(VAR1)\"" ; ls $(VAR1)
    @echo "now VAR2 = \"$(VAR2)\"" ; ls $(VAR2)
    @echo "now VAR3 = \"$(VAR3)\"" ; ls $(VAR3)
    @echo "now VAR4 = \"$(VAR4)\"" ; ls $(VAR4)
    @echo "now VAR5 = \"$(VAR5)\"" ; ls $(VAR5)
    @echo "now VAR6 = \"$(VAR6)\"" ; ls $(VAR6)
    rm -v foo.c

実行makeすると、呼び出される追加の(空の)Cファイルを作成するルールがトリガーされfoo.cますがfoo.c、その値に6つの変数はありません。


これはすばらしい呼び出しであり、宣言時の拡張の例がたくさんあります。使用時の拡張の例といくつかの単語で答えを拡張すると便利です
Robert Monfera
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.