gnu-make in - What is the difference between the GNU Makefile variable assignments =, ?=, := and +=?
target from (5)
= causes the variable to be assigned a value. If the variable already had a value, it is replaced. This value will be expanded when it is used. For example:
HELLO = world HELLO_WORLD = $(HELLO) world! # This echoes "world world!" echo $(HELLO_WORLD) HELLO = hello # This echoes "hello world!" echo $(HELLO_WORLD)
:= is similar to using
=. However, instead of the value being expanded when it is used, it is expanded during the assignment. For example:
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)
?= assigns the variable a value iff the variable was not previously assigned. If the variable was previously assigned a blank value (
VAR=), it is still considered set I think. Otherwise, functions exactly like
+= is like using
=, but instead of replacing the value, the value is appended to the current one, with a space in between. If the variable was previously set with
:=, it is expanded I think. The resulting value is expanded when it is used I think. For example:
HELLO_WORLD = hello HELLO_WORLD += world! # This echoes "hello world!" echo $(HELLO_WORLD)
If something like
HELLO_WORLD = $(HELLO_WORLD) world! were used, recursion would result, which would most likely end the execution of your Makefile. If
A := $(A) $(B) were used, the result would not be the exact same as using
B is expanded with
+= would not cause
B to be expanded.
Can anybody give a clear explanation of how variable assignment really works in Makefiles.
What is the difference between :
VARIABLE = value VARIABLE ?= value VARIABLE := value VARIABLE += value
I have read the section in GNU Make's manual, but it still doesn't make sense to me.
In the above answers, it is important to understand what is meant by "values are expanded at declaration/use time". Giving a value like
*.c does not entail any expansion. It is only when this string is used by a command that it will maybe trigger some globbing. Similarly, a value like
$(wildcard *.c) or
$(shell ls *.c) does not entail any expansion and is completely evaluated at definition time even if we used
:= in the variable definition.
Try the following Makefile in directory where you have some C files:
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 will trigger a rule that creates an extra (empty) C file, called
foo.c but none of the 6 variables has
foo.c in its value.
VARIABLE = value
Normal setting of a variable - values within it are recursively expanded when the variable is used, not when it's declared
VARIABLE := value
Setting of a variable with simple expansion of the values inside - values within it are expanded at declaration time.
Set If Absent
VARIABLE ?= value
Setting of a variable only if it doesn't have a value
VARIABLE += value
Appending the supplied value to the existing value (or setting to that value if the variable didn't exist)
When you use
VARIABLE = value, if
value is actually a reference to another variable, then the value is only determined when
VARIABLE is used. This is best illustrated with an example:
VAL = foo VARIABLE = $(VAL) VAL = bar # VARIABLE and VAL will both evaluate to "bar"
When you use
VARIABLE := value, you get the value of
value as it is now. For example:
VAL = foo VARIABLE := $(VAL) VAL = bar # VAL will evaluate to "bar", but VARIABLE will evaluate to "foo"
VARIABLE ?= val means that you only set the value of
VARIABLE is not set already. If it's not set already, the setting of the value is deferred until
VARIABLE is used (as in example 1).
VARIABLE += value just appends
VARIABLE. The actual value of
value is determined as it was when it was initially set, using either
I built the boost libraries using Boost-for-Android. Then I have in my boost/include/lib directory the android makefile boost.mk
LOCAL_PATH := $(call my-dir) # boost_date_time # include $(CLEAR_VARS) LOCAL_MODULE := boost_date_time LOCAL_SRC_FILES := libboost_date_time-gcc-mt-1_53.a include $(PREBUILT_STATIC_LIBRARY) # boost_filesystem # include $(CLEAR_VARS) LOCAL_MODULE := boost_filesystem LOCAL_SRC_FILES := libboost_filesystem-gcc-mt-1_53.a include $(PREBUILT_STATIC_LIBRARY) # boost_thread # include $(CLEAR_VARS) LOCAL_MODULE := boost_thread LOCAL_SRC_FILES := libboost_thread-gcc-mt-1_53.a include $(PREBUILT_STATIC_LIBRARY) # boost_system # include $(CLEAR_VARS) LOCAL_MODULE := boost_system LOCAL_SRC_FILES := libboost_system-gcc-mt-1_53.a include $(PREBUILT_STATIC_LIBRARY) # boost_program_options # include $(CLEAR_VARS) LOCAL_MODULE := boost_program_options LOCAL_SRC_FILES := libboost_program_options-gcc-mt-1_53.a include $(PREBUILT_STATIC_LIBRARY) # boost_chrono # include $(CLEAR_VARS) LOCAL_MODULE := boost_chrono LOCAL_SRC_FILES := libboost_chrono-gcc-mt-1_53.a include $(PREBUILT_STATIC_LIBRARY)
and my module where i use some of the boost libraries looks like this
LOCAL_PATH := $(call my-dir) # SignalServer, executable # include $(CLEAR_VARS) LOCAL_CFLAGS := -DTIXML_USE_TICPP #LOCAL_CFLAGS += -DDEBUG LOCAL_STATIC_LIBRARIES := boost_thread \ boost_system \ boost_filesystem \ boost_program_options \ boost_chrono \ LOCAL_STATIC_LIBRARIES += ticpp \ tia \ tobicore \ tobiid \ tid \ gdf LOCAL_MODULE := signalserver LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_C_INCLUDES += $(LOCAL_PATH)/extern/include LOCAL_C_INCLUDES += $(LOCAL_PATH)/../boost/include/boost-1_53 LOCAL_SRC_FILES := #cpp source include $(BUILD_EXECUTABLE)
in addition I have an Android.mk where all subdir makefiles are listed
TOP_PATH := $(call my-dir) include $(TOP_PATH)/boost/lib/boost.mk include $(TOP_PATH)/signalserver/signalserver.mk . .
and my Application.mk:
APP_PLATFORM := android-14 APP_ABI := armeabi-v7a #APP_OPTIM := debug #NDK_DEBUG := 1 NDK_TOOLCHAIN_VERSION := 4.6 APP_STL := gnustl_static APP_CPPFLAGS := -fexceptions -frtti