В чем разница между присваиванием переменных в Makefile GNU =,? =,: = И + =? - PullRequest
696 голосов
/ 16 января 2009

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

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

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

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

Ответы [ 5 ]

937 голосов
/ 16 января 2009

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

VARIABLE = value

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

Немедленный набор

VARIABLE := value

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

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

VARIABLE ?= value

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

Append

VARIABLE += value

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

240 голосов
/ 16 января 2009

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

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.

53 голосов
/ 23 декабря 2012

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

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

31 голосов
/ 16 января 2009

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

6 голосов
/ 12 декабря 2016

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

...