Condition to set a flag in makefile - makefile

I have Makefile where flag is set for IPv6 compilation.
IPV6 = 1
ifeq ($(IPV6), 1)
Then ipv6 targets are include for compilations.
Requirement:
I want to enable this flag based on feature, and this feature is part of the CFLAG.
ifdef IPV6_FEATURE
IPV6=1
else
IPV6=0
endif
But since IPV6_FEATURE is not available in Makefile as it is a global include, it will always going to else.
Please let me know if any alternatives for this.

If I understand your question, in the cases where IPV6_FEATURE is defined, it gets included after the section where you are testing it. This does not work, since make evaluates conditionals when it reads the makefile.
The solution is to not use an ifdef to set IPV6, and use a conditional function instead.
IPV6 = $(if $(IPV6_FEATURE), 1, 0)
This will set IPV6=1 if IPV6_FEATURE is defined to some non-empty value.
You may also need to change how you are using $(IPV6), so that you don't have an ifeq conditional.

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)

ifndef include guard in Gnu Make breaks on nested conditional

I’m trying to implement include guards in Gnu Make. In this Makefile, the first inclusion is OK, while the second one fails with an error.
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
define inner_macro
macro content...
endef
else
define inner_macro
endef
endif
endef
endif
The same effect can be simulated by explicitly giving INCLUDED = 1 before the inclusion, e.g. on command line.
Gnu Make 4.1 under Gentoo says Makefile:14: *** missing separator. Stop., while Gnu Make 3.81 under Debian Wheezy says Makefile:14: *** extraneous `endef'. Stop.. On the first inclusion, they both say:
Including
make: *** No targets. Stop.
If I try $(eval $(call macro,whatever)) after the first inclusion, it defines inner_macro as expected.
I used make INCLUDED=1 and make commands respectively to get the described behavior.
The same happens when I clear the environment and disable built-in rules and variables: env -i make -rR INCLUDE=1. When I use -p to dump the database, without INCLUDED=1, the macro is defined as it should be, but with INCLUDED=1, empty inner_macro is defined. This is consistent across both the versions of Make. This hints me that when the condition is false, Make parses the Makefile differently and thinks the else inside macro’s definition belongs to the ifndef. Other condition types behave all the same.
If I remove both the definitions of inner_macro, the problem goes away.
I read the manual pages info make conditional\ syntax and info make multi-line (formerly defining), but I found no caveat there and I still think I am doing nothing wrong.
Am I correct with my conclusions?
Is this a bug in Make, or am I invoking undefined behavior?
How should I implement include guards in Gnu Make?
That's a bug. Report it on Savannah.
There's something wrong with the tracking of nested define/endef inside a not-taken ifdef/ifndef condition. If you don't use nested define/endef then it works; for example (obviously you may not be able to do this in your environment):
ifndef INCLUDED
INCLUDED = 1
$(info Including)
define macro
ifneq ($(1),)
inner_macro = macro content...
else
inner_macro =
endif
endef
endif

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.

Checking environment variable in make through automake

Is there a way to have a conditional passed through automake so it is passed on to the resulting Makefile.in and Makefile later on?
I check whether JAVA_HOME is defined in the environment in a Makefile using
ifeq (undefined,$(origin JAVA_HOME))
#CALL with defaults
else
#CALL according to the variable
endif
But when I process this in a Makefile.am with automake I get two erros:
else without if
endif without if
Looks like automake does not digest the ifeq. Is there a way to pass this through it (if it makes sense doing so), or is there another autotools-friendly way of getting the same result?
The idea is also to allow setting/changing the variable just before running make to easily target different JDKs.
What I think's the right way:
Rely on $(JAVA_HOME) being set in Makefile.am and make sure a sensible value for it is set by configure.
Answering the Question as Written:
Because automake wants to generate Makefiles that work on POSIX make, it doesn't work too well with GNU-make conditionals.
So you do the test in configure.ac:
AC_SUBST([JAVA_HOME])
AM_CONDITIONAL([JAVA_HOME_SET], [test ! -z "$JAVA_HOME"])
Then in Makefile.am:
if JAVA_HOME_SET
## Something that relies on JAVA_HOME
else
## Defaults
endif

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...

Resources