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

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

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

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

Я прочитал раздел в GNU. Сделайте вручную, но мне все же не имеет смысла.

Ответ 1

Lazy Set

VARIABLE = value

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

Непосредственный набор

VARIABLE := value

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

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

VARIABLE ?= value

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

Append

VARIABLE += value

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

Ответ 2

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

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=), оно по-прежнему считается заданным, я думаю. В противном случае функции точно соответствуют =.

Использование += похоже на использование =, но вместо замены значение добавляется к текущему, пробел между ними. Если переменная была ранее установлена ​​с помощью :=, она, я думаю, расширена. Я думаю, результирующее значение расширяется, когда оно используется. Например:

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

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

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

Ответ 4

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

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 в VARIABLE. Фактическое значение value определяется так, как оно было, когда оно было первоначально установлено, используя либо =, либо :=.

Ответ 5

В приведенных выше ответах важно понимать, что подразумевается под "значениями, которые расширяются при объявлении/использовании времени". Давать значение, подобное *.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 в своем значении.