В чем разница между переменными GNU Makefile assignments =,?=,:= и +=?

может ли кто-нибудь дать четкое объяснение того, как назначение переменных действительно работает в Makefiles.

в чем разница между :

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

прочитал раздел в руководстве GNU Make, но для меня это все еще не имеет смысла.

5 ответов


Ленивый Набор

VARIABLE = value

нормальная настройка переменной-значения внутри нее рекурсивно расширяются, когда переменная используется, а не когда она объявлена

Незамедлительной Установки

VARIABLE := value

установка переменной с простым расширением значений внутри-значения внутри нее расширяются во время объявления.

Установить, Если Отсутствует

VARIABLE ?= value

настройка переменной только в том случае, если она не имеет значение

добавить

VARIABLE += value

добавление предоставленного значения к существующему значению (или установка этого значения, если переменная не существовала)


используя = вызывает присвоение переменной значения. Если переменная уже имела значение, она заменяется. Это значение будет расширено при его использовании. Например:

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)

используя ?= присваивает переменную a значение iff переменная ранее не была назначена. Если переменной ранее было присвоено пустое значение (VAR=), он по-прежнему считается set я думаю. В противном случае функции точно такие же, как =.

используя += как использовать =, но вместо замены значения, значение добавляется к текущему, с пробелом между ними. Если переменная ранее была установлена с :=, он расширяется I думай!--31-->. Полученное значение расширяется при его использовании я думаю. Например:

HELLO_WORLD = hello
HELLO_WORLD += world!

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

если что-то вроде HELLO_WORLD = $(HELLO_WORLD) world! были использованы, результатом будет рекурсия, которая, скорее всего, завершит выполнение вашего файла Makefile. Если A := $(A) $(B) были использованы, результат не будет таким же, как при использовании +=, потому что B расширяется с :=, тогда как += не приведет B будет расширен.


Я предлагаю вам сделать некоторые эксперименты, используя "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

Проверьте более подробное объяснение здесь


при использовании VARIABLE = value, Если value фактически является ссылкой на другую переменную, тогда значение определяется только тогда, когда есть. Это лучше всего проиллюстрировать на примере:

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

# VARIABLE and VAL will both evaluate to "bar"

при использовании VARIABLE := value, вы получаете значение value как сейчас. Например:

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

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

используя VARIABLE ?= val означает, что вы устанавливаете только значение VARIABLE если VARIABLE еще не установлен. Если он еще не установлен, установка значение откладывается до VARIABLE используется (как в Примере 1).

VARIABLE += value просто добавляет value to VARIABLE. Фактическое значение value определяется, как это было, когда он был первоначально установлен, используя либо = или :=.


в приведенных выше ответах,важно понять что означает "значения расширяются во время объявления/использования". Давая значение, как *.c не влечет за собой какого-либо расширения. Только когда эта строка используется командой, она может вызвать некоторый глоббинг. Аналогично, значение типа $(wildcard *.c) или $(shell ls *.c) не влечет за собой расширения и полностью оценивается во время определения, даже если мы использовали := в определении переменной.

попробуйте после Makefile в каталоге, где у вас есть некоторые файлы C:

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 но ни одна из 6 переменных не имеет foo.c в его стоимости.