I am new to makfile.
what is the meaning of ?= in makefile
Dose it mean if not defined then define or its something else
Yes, it means "define if not defined". From info make:
There is another assignment operator for variables, `?='. This is
called a conditional variable assignment operator, because it only has
an effect if the variable is not yet defined.
Related
I want to define a variable differently depending on another variables value in a makefile. I thought using conditionals would solve the problem, like this in the makefile:
ifeq ($(BOOT_FLAG),installed)
BOOT_TEST=$(BOOT_FLAG)
else
BOOT_TEST=no
endif
BOOT_DEFINE=$(BOOT_FLAG)
BOOT_FLAG=installed
.PHONY: all
all:
#echo $(BOOT_TEST)
#echo $(BOOT_DEFINE)
I expected the output to be:
installed
installed
but I got this instead:
no
installed
apparently the ifeq does not expand the BOOT_FLAG to installed
but setting of the BOOT_DEFINE variable manages to expand it correctly.
I read in the manual that:
"make evaluates conditionals when it reads a makefile. Consequently, you cannot use automatic variables in the tests of conditionals because they are not defined until commands are run"
but the BOOT_FLAG is not an automatic variable. Also if I move the definition of BOOT_FLAG to before the ifeq, then it works as I want it. However, I want to keep the current order of the definitions (and I don't understand why make does an exception to the order independence of the definitions when using conditions)
The answer is right there in the statement you quoted:
make evaluates conditionals when it reads a makefile.
Since make has evaluated the conditional when it read that line in the makefile, and the variable has not been defined when it read that line, there's no way that variables set after the conditional can take effect.
Just because the documentation lists one consequence of this behavior (the one that most people get confused by) doesn't mean that this is the only consequence of this behavior.
However, I want to keep the current order of the definitions
You can't.
(and I don't understand why make does an exception to the order independence of the definitions when using conditions)
It would be virtually impossible, and even if it could be done the resulting behavior would be almost indecipherable except in the most trivial situations. If you don't believe me, try to write down an algorithm describing how that could work. Remember to consider things like simple variable assignments, nested conditionals, variables used in target and prerequisite lists, variables that are intentionally reset in different parts of makefiles, etc.
ETA You could do it, by putting the ifeq into a define variable then using eval later, after BOOT_FLAG is set, to expand it. Seems gross to me but...
This is because makefile is evaulating the ifeq as it parses the file.
So when it gets to the ifeq..., then BOOT_FLAG is yet not set, so BOOT_TEST = no
Then you set BOOT_FLAG.
Then once all the variables are parsed, makefile will go through and run your rule - so in this case BOOT_DEFINE is evaluated to $(BOOT_FLAG) final value of installed
Try this:
$(info start - BOOT_FLAG=$(BOOT_FLAG))
ifeq ($(BOOT_FLAG),installed)
BOOT_TEST=$(BOOT_FLAG)
else
BOOT_TEST=no
endif
$(info after if - BOOT_FLAG=$(BOOT_FLAG))
BOOT_DEFINE=$(BOOT_FLAG)
BOOT_FLAG=installed
$(info after assignment - BOOT_FLAG=$(BOOT_FLAG))
.PHONY: all
all:
#echo $(BOOT_TEST)
#echo $(BOOT_DEFINE)
You will see various values printed at different times during the makefile parsing. On the first pass it evaluates the variables (and if's) and then on the second pass it can do the target rules.
As others noted the problem is that ifeq is expanded and evaluated in-place.
If you want to postpone the evaluation until some late moment, you must keep the whole expression inside of a recursive variable. Then the conditional could be implemented by $(if ...) function, instead of ifeq (okay, $(eval ifeq...) should also be doable, but... well, gross).
Of course, this is quite an overhead for such simple case, but nonetheless it could be done like this:
BOOT_TEST=$(if $(subst _installed,,_$(BOOT_FLAG)),no,installed)
BOOT_DEFINE=$(BOOT_FLAG)
BOOT_FLAG=installed
.PHONY: all
all:
#echo $(BOOT_TEST)
#echo $(BOOT_DEFINE)
I want to set a Global variable through a recipe then reference that variable in another independent recipe
The below code is an example code that sets the variable within the recipe but the variable stays with the initial value if referenced outside the recipe
ACTIVE = a
switch:
ifeq ($(ACTIVE),b)
ACTIVE=$(shell echo 'a')
else
ACTIVE=$(shell echo 'b')
endif
print:
$(info acitve = $(ACTIVE))
I know there are ways to broadcast the value of a target-specific variable to dependent targets, but that's not what I want.
You can use $(eval ...) for this, although it's almost always a bad idea. I have to assume that your real situation is much more complicated because there are many better ways to accomplish what you've actually provided in the sample makefile.
switch:
$(eval ACTIVE=$(if $(filter-out a,$(ACTIVE)),a,b))
I'm building a third-party SDK where Makefile checks if DEF_2_3 was defined:
..
#ifdef DEF_2_3
CFLAGS_LOCAL += -I$(SDK)/include
#endif
all:
...
clean:
...
However, I didn't find anywhere in the SDK (I grepped through the directory), where DEF_2_3 would be defined. I wonder if makefile consideres ifdef MACRO as defined by default? And if so, I have to undefine MACRO at the top of the makefile.
Thanks.
Those are commented out.
make doesn't use #ifdef it uses ifdef.
See 7.2 Syntax of Conditionals.
ifdef variable-name
The ifdef form takes the name of a variable as its argument, not a reference to a variable. The value of that variable has a non-empty value, the text-if-true is effective; otherwise, the text-if-false, if any, is effective. Variables that have never been defined have an empty value. The text variable-name is expanded, so it could be a variable or function that expands to the name of a variable.
I have a makefile from Intel in which there is some "?=".
Like
COMPILER ?= $(GCC_PATH)g++
But
EXECUTABLE = run
What is the difference between ?= and = and when do I have to use the first one instead of the second one ?
Thank you very much.
Quoth the fine documentation:
If you'd like a variable to be set to a value only if it's not already set, then you can use the shorthand operator ‘?=’ instead of ‘=’.
?= is for conditional assignment, i.e if it not already defined then only assign the value else leave it. In your example if you give make COMPILER=arm-none-gcc then arm-none-gcc is used as Compiler than the default g++, if you just type make then g++ taken as option for COMPILER. If = is used then COMPILER will be assigned value when and where assignments are encountered. for more on make files you can refer to
Understanding makefile for beginners
I have a Makefile for a C program that has the declaration
CC?=gcc
Changing it to
CC?=g++
does NOT make it compile with g++. Changing it to
CC=g++
DOES make it use g++.
So I wonder what the ?= operator does? My guess is that it looks at a environment variable to decide which compiler to use and if it's not set then use gcc? Anyone who can clear this up?
From http://www.gnu.org/software/make/manual/make.html:
There is another assignment operator
for variables, `?='. This is called a
conditional variable assignment
operator, because it only has an
effect if the variable is not yet
defined. This statement:
FOO ?= bar
is exactly equivalent to this (see The
origin Function):
ifeq ($(origin FOO), undefined)
FOO = bar
endif
Probably CC is already defined as gcc, so CC ?= g++ won't override the existing gcc.
The ?= operator sets the variable only if it isn't already set: info make → * Using Variables → * Setting.
As others mentioned, it is likely already predefined.
On GNU, you can see what is defined with make -p from a directory that does not contain a Makefile.
This is documented at: https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
CC
Program for compiling C programs; default ‘cc’.
Usually, CC=cc by default. Then on Ubuntu 14.04 for e.g., cc is usually a symlink to gcc.
To disable all variables at once see: Disable make builtin rules and variables from inside the make file Seems currently impossible.
The "?" operator means set if not already set.
So, if CC is already blank CC?= will set it. If CC already contains something, it won't.
Source: http://unix.derkeiler.com/Mailing-Lists/FreeBSD/questions/2007-03/msg02057.html