How to make Makefile Variables persist between commands - makefile

Here is a sample makefile that demonstrates what I'm trying to accomplish:
PLATFORM=wrongName
debug:
#echo debug $(PLATFORM)
debug-android: android debug
android:PLATFORM=android
android:
#echo set PLATFORM to $(PLATFORM)
here is the terminal output:
user:~/Project/maketest$ make debug-android
set PLATFORM to android
debug wrongName
when calling the target make debug-android my intention is to set the PLATFORM variable to "android", and that works in the android: command, however the "PLATFORM" var reverts to "wrongName" default value set at the top of the makefile. I'm trying to replace the value here so that any subsequent dependencies for the target will also see the value of "PLATFORM" as "android".
so my question is: how do i make "PLATFORM" variable assignment persist between commands/targets?

There are a couple of different ways to do this, but you still haven't made clear exactly what you want these rules to do, conceptually.
Here is one way:
debug-android:PLATFORM=android
debug-android: android debug
android:
#echo set PLATFORM to $(PLATFORM)
EDIT:
Ah, so the idea is to avoid repetition of PLATFORM=android. Try this:
PLATFORM=wrongName
all: debug-android prod-android test-android
debug:
#echo Debug $(PLATFORM)
prod:
#echo Prod $(PLATFORM)
test:
#echo Test $(PLATFORM)
%-android: PLATFORM=android
debug-android: debug
test-android: test
prod-android: prod
If this is on the right track, we can go farther, removing the redundancy of those last three lines.

In general, it's a bad idea to do this. Most of the time if you want to do it, it probably means that you should be thinking about the problem differently.
However, it is possible to do this (in GNU make only) using eval. Usually when I see eval used in a recipe it's a code smell but it does work:
android:
$(eval PLATFORM := $(PLATFORM))
#echo set PLATFORM to $(PLATFORM)

Related

How can I pass a argument to a makefile dependency?

I have the following Makefile where the all make target depends on a separate setup make target that also takes an argument. However when I make all the setup target is not invoked with the argument
setup:
...command
clean:
...command
all: setup myarg=value clean myarg=value
#echo "setup & clean"
I think what you're asking is if a prerequisite can inherit a target-specific variable. In which case, yes it can -- Note, in your example you tried to intersperse the target specific variables and the prerequisites, which you can't do. But beware -- this has sharp sticks attached. Consider the following makefile:
all:
setup:
#echo "building $#: myarg=$(myarg)"
all: myarg:=value
all: setup
#echo "building $#: myarg=$(myarg)"
blah: setup
#echo "building $#: myarg=$(myarg)"
If I do make all, I get:
tmp> make all
building setup: myarg=value
building all: myarg=value
Which is what you want. But if I do make blah, then setup is run as a prerequisite of blah, and does not have the value set as you might expect. It will not be rebuilt for main, even though the variable is different:
tmp> make blah all
building setup: myarg=
building blah: myarg=
building all: myarg=value
See the make manual for more details
The command line of the make program is not free-form. You can't just pass it a bunch of stuff and have that "stuff" passed through make to appear somehow inside your recipes. make can only take arguments that it's defined to take: all arguments (not options) are either targets or variable assignments. See the documentation or the man page.
It is not possible in general to pass arbitrary values on the make command line. However, as I said, make does allow variables to be set on its command line.
If you run make setup myarg=value then this will set the make variable myarg to have the value value, and ask make to build the setup target.
So, if you write your makefile:
setup:
...command $(myarg)
referencing the make variable myarg, then it will "work" (I guess, you haven't made clear exactly what you want to run using myarg).

Need help in understanding why ifeq does not work

I have the following code in a makefile:
TEMP="VBU538ForBootloader"
# build
build: .build-post
.build-pre:
# Add your pre 'build' code here...
.build-post: .build-impl
#echo "Current config:" $(CONF)
#echo "Compare to:" $(TEMP)
ifeq ($(CONF),$(TEMP))
#echo "Making production files for VBU538 .... "
else
#echo "Skipping production files."
endif
Somehow the ifeq does not do what I expected, although it looks to me that my code is similar to other examples. The code produces the following output:
Current config: VBU538ForBootloader
Compare to: VBU538ForBootloader
Skipping production files.
I am always getting Skipping production files. although I expected that the output should have been Making production files for VBU538 ....
Does anyone know the reason why its not behaving as expected?
Your code is not an MCVE so it is difficult to help. It could be that your COMP and TEMP variables look identical but they are not (spaces, other invisible characters...) You could try to check this by using:
#echo 'Current config: X$(CONF)X'
#echo 'Compare to: X$(TEMP)X'
instead of
#echo "Current config:" $(CONF)
#echo "Compare to:" $(TEMP)
I eventually found the problem. Thanks for everybody's effort. Eventually I got a hunch that when I was calling make, the wrong make utility was being used. It turned out that I have to use the same make utility as the one that came with the IDE for the microcontroller. I am not sure why that would be needed, but using the make utility that came with the IDE solved the problem.

change variable name based on target and export target specific variable

I am trying to build release and debug version of my binary. all is building the release, which is working alright. I would like to add a make debug to change my binary name and compile with a set of different flags. To do this, I'm using target specific variables in my top Makefile.
BINARY=hello
debug: DBG:=1
debug: $(BINARY)+=_debug
export DBG
debug: bin/$(BINARY).bin
all: bin/$(BINARY).bin
$(BINARY).bin has its own set of rules which work fine for the release part, as it was the only target I had before. After adding the debug target, I was hoping,
The DBG variable gets exported, so that my recursive Makefile can pick it up to change compilation flags, which I think is working
The binary name changes, appending _debug which it is not. Not sure what I'm doing incorrectly.
EDIT:
Adding some more information about how my bin target is built. My bin/$(BINARY).bin target depends on some .img and other .bin files whose target name I would also like to change based on whether I am building release or debug.
bin/$(BINARY).bin: bin/$(SOME_IMAGE).img bin/$(BINARY_1).bin
.....
bin/$(SOME_IMAGE).img: bin/$(BINARY_2).bin
......
bin/$(BINARY_1).bin: bin/$(BINARY_1).hex
......
bin/$(BINARY_1).hex:
$(MAKE) -C some-dir
bin/$(BINARY_2).bin: bin/$(BINARY_2).hex
......
bin/$(BINARY_2).hex:
$(MAKE) -C some-other-dir
to build debug, I am trying:
debug: export DBG:=1
debug: $(BINARY)+=_debug
debug: $(SOME_IMG)+=_debug
debug: $(BINARY_1)+=_debug
debug: $(BINARY_2)+=_debug
but that isn't doing the trick
This is roughly how I would approach the problem:
BINARY=hello
all: bin/$(BINARY).bin
debug: DBG:=1
debug: bin/$(BINARY)_debug.bin
bin/$(BINARY).bin bin/$(BINARY)_debug.bin:
#echo building $#, flag is $(DBG)
I am not sure that this solves your whole problem-- I couldn't parse your first bullet point. If it doesn't, perhaps you could edit your question to add a complete example.
The value of target-specific variable is available only within the target's recipe, not for the target's prerequisites. When you create the target-specific variable by incrementing the global variable, you now have two variables, one global, one target-specific. Yes you can export target-specific variable to prerequisites in a submake, with an export attribute. (All of this comes from the manual, section on target-specific variables.).
Prerequisites are evaluated at parse-time, from the current values of global variables (not from target-specific ones).
So, this is what you probably want. You seem to prefer trial-and-error, to actually RTFM. IMHO, you should really RTFM more, not guess functionality.
BINARY:=hello
all: bin/$(BINARY).bin
BINARY := $(BINARY)_debug
debug: export DBG:=1
debug: bin/$(BINARY).bin
If this "does not work", here is how you post questions on Stack Overflow.
You have a programming goal in mind and you write some code and it does not work the way you expect.
You make the code smaller and smaller to search for the cause of the problem.
If you have the smallest amount of code that reproduces the problem, and you still don't understand why your code does not work, then you post the complete minimal code in your question, and all details of your expectation, and your results different than the expectation.

Makefile conditional not respecting target-specific variables

Is there a way to use the native Makefile if-else conditional and also have it respects target-specific variables re-assignments?
Example Makefile:
#!/usr/bin/make
CONFIG = Debug
.PHONY: test printme
test: override CONFIG=Release
test: printme
#echo "Done."
printme:
ifeq "$(CONFIG)" "Debug"
#echo "should be DEBUG -> $(CONFIG)"
else
#echo "should be RELEASE -> $(CONFIG)"
endif
Running make test prints the following output:
should be DEBUG -> Release
Done.
The output I'm looking for is should be RELEASE -> Release how can I achieve that? Do I need to use shell conditionals instead?
This behavior seems logical to me: At the time of parsing the Makefile, CONFIG is defined as Debug. The ifeq conditional uses the value of CONFIG it knows at that time. Therefore it chooses the ifeq branch that outputs "Should be DEBUG".
The target-specific variable is only defined as Release with the target test. Its prerequisite printme also knows the target-specific variable and ouputs Release.
May I suggest that you set variable to make on the command line for the purpose you want. It's not many more characters to write when invoking make but brings all you seem to be willing.
make CONFIG=Release

Conditional inclusion/execution of Makefile commands in a variable?

There is a Makefile that I am using, which I got from somewhere, and which is quite big. I have also found some things that I'd like changed occasionally in the makefile - and the easiest way to do that for me is to define (or not) a (switch) variable (say, OVWRCHOICE) at the start of the makefile; and then later on in the makefile code, do something like:
ifdef OVWRCHOICE
MYOPT = override
....
endif
... which is all dandy and fine.
The thing is, eventually I also need to change parts in the "override" part as well, so I'd like to have it at the start of the file. So, as this "override" part contains several make commands -- I tried to use define, to have a variable which will contain the commands (which would be executed at the ifdef OVWRCHOICE... part).
So I arrived at this simple example:
# uncomment as needed;
OVWRCHOICE = YES
define SET_OVWRCHOICE
MYOPT = override
endef
export SET_OVWRCHOICE
# ... many lines of code ...
MYOPT = default
# ... many lines of code...
# without indent: Makefile:18: *** missing separator. Stop.
# with tab indent: Makefile:18: *** commands commence before first target. Stop.
ifdef OVWRCHOICE
$(SET_OVWRCHOICE)
endif
all:
#echo $(MYOPT)
... which fails with the errors noted. Of course, if I use the first snippet in the post instead, all runs fine, and make prints out the expected result: "override".
How would I go about in achieving something like this? Not sure if "inclusion" or "execution" of "Makefile commands" are even the right terms in this context; so I have a hard time in finding a starting point for a search :)
Got it - it is described in Eval Function - GNU `make'; the right construct is:
ifdef OVWRCHOICE
$(eval $(call SET_OVWRCHOICE))
endif
Hope this helps someone,
Cheers!
Oh well, didn't really know where to archive this snippet, so back to this old question of mine :) this is off topic for OP; but here goes:
To test how environment variables are processed by a makefile, here is a simple example:
Foo=something
all :
ifdef DEBUG
#echo "Debug defined"
else
#echo "Debug NOT defined"
endif
... and here is the test for it:
$ make
Debug NOT defined
$ make DEBUG
make: *** No rule to make target `DEBUG'. Stop.
$ DEBUG make
DEBUG: command not found
$ DEBUG= make
Debug NOT defined
$ DEBUG=1 make
Debug defined
... so obviously, the right syntax to set that variable inside the makefile from the command line is: "DEBUG=1 make"

Resources