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.