Summary:
This month's article is about a little GNU Make Gotcha: an easy way to get tripped up by two pieces of GNU Make syntax that do similar things, yet one has a deceptive name. ifndef isn't really ifndef at all, it would better if it were called ifempty, while ?= does make its decision based on whether the variable is defined or not.
Compare these two ways of conditionally setting the variable FOO in a Makefile:
ifndef FOO
FOO = New Value
endif
and
FOO ?= New Value
They look like they should do the same thing, and they do... almost.
What ?= doesThe ?= operator in GNU Make sets the variable mentioned on its left-hand side to the value on the right-hand side if the left-hand side is not defined. So, for example the following Makefile sets FOO to New Value:
FOO ?= New Value
But this one does not:
FOO = Old Value
FOO ?= New Value
And neither does this one (even though FOO was initially empty):
FOO =
FOO ?= New Value
In fact ?= is exactly the same as the following which uses the GNU Make $(origin) function to determine if a variable is undefined. $(origin FOO) will return a string that shows whether and how FOO is defined (see the GNU Make manual for more information). If FOO is undefined then $(origin FOO) is undefined.
ifeq ($(origin FOO),undefined)
FOO = New Value
endif
Note that variables defined with ?= are expanded just like variables defined with =. They are expanded when used and not when defined just like a normal GNU Make variable.
What ifndef doesifndef, on the other hand, tests whether a variable is empty or not. ifndef does not check to see if the variable is defined. ifndef actually means "if the variable is undefined or is defined but is empty". Thus
ifndef FOO
FOO = New Value
endif
will set FOO to the New Value if FOO is undefined or FOO is empty. So ifndef can be rewritten
Since an undefined variable is always treated as having an empty value when read.
FOO ?= New Value
They look like they should do the same thing, and they do... almost.
What ?= doesThe ?= operator in GNU Make sets the variable mentioned on its left-hand side to the value on the right-hand side if the left-hand side is not defined. So, for example the following Makefile sets FOO to New Value:
FOO ?= New Value
But this one does not:
FOO = Old Value
FOO ?= New Value
And neither does this one (even though FOO was initially empty):
FOO =
FOO ?= New Value
In fact ?= is exactly the same as the following which uses the GNU Make $(origin) function to determine if a variable is undefined. $(origin FOO) will return a string that shows whether and how FOO is defined (see the GNU Make manual for more information). If FOO is undefined then $(origin FOO) is undefined.
ifeq ($(origin FOO),undefined)
FOO = New Value
endif
Note that variables defined with ?= are expanded just like variables defined with =. They are expanded when used and not when defined just like a normal GNU Make variable.
What ifndef doesifndef, on the other hand, tests whether a variable is empty or not. ifndef does not check to see if the variable is defined. ifndef actually means "if the variable is undefined or is defined but is empty". Thus
ifndef FOO
FOO = New Value
endif
will set FOO to the New Value if FOO is undefined or FOO is empty. So ifndef can be rewritten
ifeq ($(FOO),)
FOO = New Value
endif
FOO = New Value
endif
Since an undefined variable is always treated as having an empty value when read.