В чем разница между назначениями переменных 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
в своем значении.