GNU Makefile değişken atamaları =,? =,: = Ve + = arasındaki fark nedir?


764

Herkes Makefiles'de değişken atamanın gerçekten nasıl çalıştığına dair net bir açıklama yapabilir mi?

Arasındaki fark nedir :

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

GNU Make'in el kitabındaki bölümü okudum , ama yine de benim için anlamlı değil.

Yanıtlar:


1028

Tembel Set

VARIABLE = value

Bir değişkenin normal ayarı, ancak valuealanla belirtilen diğer değişkenler , bildirildiği sırada sahip olduğu değişkenin değil, değişkenin kullanıldığı noktadaki değerleriyle özyinelemeli olarak genişletilir.

Anında Set

VARIABLE := value

İçindeki değerlerin basit genişlemesine sahip bir değişkenin ayarlanması - içindeki değerler, bildirim zamanında genişletilir.

Tembel Tembel Set Yok

VARIABLE ?= value

Değişkenin yalnızca değeri yoksa ayarlanması. valueher zaman VARIABLEerişildiğinde değerlendirilir . Eşdeğerdir

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

Daha fazla ayrıntı için belgelere bakın.

ekleme

VARIABLE += value

Sağlanan değeri mevcut değere ekleme (veya değişken yoksa bu değere ayarlama)


25
A + = B B'yi genişletir mi? A + = B ve sonra B + = C yaparsam, A $ {B} ve $ {C} birleşimine değerlendirir mi?
Anton Daneyko

15
Kılavuzun bağlantılı bölümünün söylediği gibi. + =, orijinal ödevin sahip olduğu basit veya yinelemeli semantiğe göre çalışır. Yani evet, RHS'yi genişletecek, ancak bunu hemen mı yoksa ertelenmiş bir şekilde mi yapılacağı LHS'deki değişkenin türüne bağlıdır.
Etan Reisner

6
Değişken değerinin genişletildiğini söylediğinizde ne demek istiyorsunuz?
Sashko Lykhenko

2
@ СашкоЛихенко genişleme anlamını almak için buraya bir göz atın gnu.org/software/make/manual/make.html#Flavors
Umair R

7
"yoksa ayarlanır" tembel veya anında mı? "yoksa tembel seti" ve "abset ise hemen" ayarlayabilir miyim?
Woodrow Barlow

268

Kullanılması =değişkene bir değer atanmasına neden olur. Değişkenin zaten bir değeri varsa değiştirilir. Bu değer kullanıldığında genişletilecektir. Örneğin:

HELLO = world
HELLO_WORLD = $(HELLO) world!

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

HELLO = hello

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

Kullanmak :=, kullanmaya benzer =. Ancak, kullanıldığında genişletilen değer yerine, atama sırasında genişletilir. Örneğin:

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)

Kullanılması ?=atar değişken bir değeri iff değişken önceden atanmış değildi. Değişken daha önce boş bir değer ( VAR=) atandıysa , yine de bence ayarlanmış sayılır . Aksi takdirde, işlevler tam olarak benzer =.

Kullanmak kullanmak +=gibidir =, ancak değeri değiştirmek yerine değer, aradaki boşlukla geçerli değere eklenir. Değişken önceden ayarlanmışsa :=, bence genişletilir . Elde edilen değer kullanıldığında genişletilir bence . Örneğin:

HELLO_WORLD = hello
HELLO_WORLD += world!

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

Böyle bir şey HELLO_WORLD = $(HELLO_WORLD) world!kullanılmış olsaydı, büyük olasılıkla Makefile'nizin yürütülmesine son verecekti. Eğer A := $(A) $(B)kullanıldı, sonuç kullanarak tamamen aynı olmaz +=çünkü Bile genişletilir :=oysa +=neden olmaz Bgenişletilecek.


3
bunun bir sonucu bu nedenle VARIABLE = literalve VARIABLE := literalher zaman eşdeğerdir. Bunu doğru anladım mı?
aiao

1
@aiao, evet değişmezler kullanımlarına değişmez
Sebastian

Küçük bir fark: -?: Özyinelemeli olarak adlandırılan özyinelemelerde performansı artırabilir. Örneğin, $? = $ (kabuk_bir_birim_that_runs_long_time) Yinelemeli aramalarda bu yalnızca bir kez değerlendirilir. yapı performansında kazançlara neden olur. : = komut birkaç kez gereksiz yere çalıştığı için daha yavaş olacaktır
KeshV

61

"Make" kullanarak bazı deneyler yapmanızı öneririm. İşte =ve arasındaki farkı gösteren basit bir demo :=.

/* 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 baskılar:

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

Daha ayrıntılı açıklamaya buradan göz atın


5
@Sonuçların bu kafa karıştırıcı tekrarını önlemek için her bir tarifin önünde bir kullanmak daha iyi olur .
Alexandro de Oliveira

2
Marka /* ... */blok yorumu desteklemiyor
yoonghm

31

Eğer kullandığınız zaman VARIABLE = valuebile, valueaslında başka değişkenin başvurusu olduğunda, o değer yalnızca belirlenir VARIABLEkullanılır. Bu en iyi şekilde bir örnekle gösterilmiştir:

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

# VARIABLE and VAL will both evaluate to "bar"

Kullandığınızda VARIABLE := value, value şu anda olduğu gibi değerini alırsınız . Örneğin:

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

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

Kullanımı VARIABLE ?= valyalnızca değerini ayarlamak olduğunu araçlarını VARIABLE eğer VARIABLE zaten ayarlı değil. Önceden ayarlanmamışsa, değerin ayarı VARIABLEkullanılana kadar ertelenir (örnek 1'deki gibi).

VARIABLE += valueSadece ekler valueiçin VARIABLE. Öğesinin gerçek değeri, veya valueöğelerinden biri kullanılarak ilk ayarlandığı zamanki gibi belirlenir .=:=


Aslında, ilk örneğinizde, VARIABLE $ (VAL) ve VAL çubuktur. VARIABLE kullanıldığında genişletildi.
Strager

1
Evet, yorumlar kullanıldıklarında ne olacağını açıklıyor.
mipadi

Ah; Sanırım düzelttiniz, ya da "değerlendirmek" i "olduğu gibi" yanlış okudum.
Strager

7

Yukarıdaki cevaplarda, "beyan / kullanım zamanında değerler genişletildi" nin ne anlama geldiğini anlamak önemlidir . Gibi bir değer vermek, *.cherhangi bir genişleme gerektirmez. Sadece bu dize bir komut tarafından kullanıldığında, belki de bazı globbing tetikleyecektir. Benzer şekilde, herhangi bir genişleme gerektiren $(wildcard *.c)veya $(shell ls *.c)içermeyen bir değer :=ve değişken tanımında kullansak bile tanım zamanında tamamen değerlendirilir .

Bazı C dosyalarınızın bulunduğu dizinde aşağıdaki Makefile dosyasını deneyin:

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

Çalıştırıldığında make, çağrılan fazladan (boş) bir C dosyası oluşturan bir kural tetikler, foo.cancak 6 değişkenden hiçbirinin foo.cdeğeri yoktur.


Bu harika bir çağrıdır ve beyan zamanında genişleme için çok sayıda örneğe sahiptir, cevabı bir örnekle ve kullanım zamanında genişleme için bazı kelimelerle genişletmek yararlı olacaktır
Robert Monfera
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.