Makefile : syntax ?= - makefile

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

Related

Makefile expanding variables inside conditionals depends on order of definition

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)

How to find out the definition of the variable MAKE

Haven't been using make for a while. But just got a project from a 10 years old compiler using Ubuntu.
I am looking at the makefile and trying to find out which compiler it is using.
${MAKE} is used in the file.
But where can I find out the definition of MAKE.
Thanks
You could simply use both the info and value built-in functions inside your makefile:
$(info MAKE: $(value MAKE))
This will work if MAKE is a recursively expanded variable, which it is by default. Otherwise, if MAKE were a simply expanded variable, you will see the expansion that was done at the moment of evaluating MAKE's definition (i.e., the same as $(MAKE)).
A better approach, which is independent of the flavour of the variable, would be to run make with the option -p and look at the definition of MAKE, e.g.:
make -p | grep 'MAKE ='
You will probably find out that MAKE is defined as:
MAKE = $(MAKE_COMMAND)
and MAKE_COMMAND, which is another variable (this time, a simply expanded one), may be in turn defined as:
MAKE_COMMAND := make

Overriding a makefile variable

I have a master makefile which has the default values for variables and then a child makefile which includes project specific settings. At the end of the child makefile, I include the master makefile.
I have been using the following code in the master makefile to set default values for a variable
ifndef CC
CC = avr-gcc
endif
And then recently I read that I can also do
CC ?= avr-gcc
So my question is, whether both are same and if yes which one is the recommended way of overriding variables.
The second is broadly understood, easier to read and causes less clutter.
The first way, using ifndef / endif is more for instances where you want to do more than just set a variable, like toggling many things depending on if DEBUG is set, or something else.
If you just want to set a variable if it's not already set, then var ?= value is definitely sufficient.

Make: Setting variable based on target

I want to set a variable depending on the assigned target.
For instance:
if target == filename_a then
VAR1 = YES
if target == filename_b then
VAR2 = YES
Obviously, this is pseudo-code and not proper make-syntax.
What I really want to do is to include different make-files and include-directories dependent on target. Some targets share the same settings, and hence it is easier to maintain in one makefile.
An example of what it will be used for later:
ifeq ($(VAR1), YES)
include foo.mk
endif
ifeq ($(VAR2), YES)
include baz.mk
endif
Unfortunantly the following syntax cannot be used:
target : VAR1 = YES
Since this variable assignment is only valid through the process of actually building target, as I understand it.
The target environment is ClearMake 7 under Solaris, so please avoid any GNU Make specific solutions.
Thanks
Edit:
As far as I can tell, make does not work in a way where the target is available during the processing step. Hence the feature asked for does most likely exist.
I'd be surprised if this can work, since as I understand it, Make processes include statements before it knows what targets it needs to make. But I know nothing about ClearMake and I'm not really an expert, so hopefully someone proves me wrong...

What does CC?= in a Makefile mean?

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

Resources