How can I terminate my build if certain preconditions are not met? - makefile

I would like to do something like the following in my GNU makefile:
ifndef TOP
abort Error TOP not defined
endif
Is there a way to terminate with a simple message to the terminal if all the required variables are not defined?

$(error Error TOP not defined)
From http://www.gnu.org/software/make/manual/make.html#Make-Control-Functions:
$(error text...)
Generates a fatal error where the message is text. Note that the error is generated whenever this function is evaluated. So, if you put it inside a recipe or on the right side of a recursive variable assignment, it won't be evaluated until later. The text will be expanded before the error is generated.
For example,
ifdef ERROR1
$(error error is $(ERROR1))
endif
will generate a fatal error during the read of the makefile if the make variable ERROR1 is defined. Or,
ERR = $(error found an error!)
.PHONY: err
err: ; $(ERR)
will generate a fatal error while make is running, if the err target is invoked.

Related

Makefile if statement causing some weird behavior

In my makefile, the user supplies an argument called EXEC (make target EXEC=something). I want this to happen:
if EXEC equals "server"
make the variable NOT equal to "client"
if EXEC equals "client"
make the variable NOT equal to "server"
I tried doing this:
ifeq ($(EXEC),server)
NOT := client
endif
ifeq ($(EXEC),client)
NOT := server
endif
I run this by saying make -f build.mk EXEC=server
the output is:
NOT := client
make[2]: NOT: No such file or directory
Why is this error happening?
It seems you've indented the variable assignment with a TAB character. That means that line is considered part of the recipe for the previous target.
Since you haven't provided the entire makefile, or at least the section of the makefile before/after this, we can't say more than that.
However, in general in a makefile you should never indent any lines with TAB characters unless they are intended to be a part of a recipe.

Can I make a makefile abort outside of a rule?

At the top of my Makefile, before any of the rules, I have the following:
ifeq ($(ENVIRONMENT),LOCAL)
TARGET := local_target
else
TARGET := hello
endif
If the ENVIRONMENT environment variable is not set, or is set to a value other than LOCAL, instead of setting TARGET to hello, I want the makefile to halt and exit with -1.
Can I do that?? When I change TARGET := hello to exit -1, I get the following error:
Makefile:4: *** missing separator. Stop.
How can I make this work??
exit is a shell command, so you could use the shell assignment operator (i.e.: !=) inside the Makefile to call exit:
TARGET != exit -1
This would be actually equivalent to:
TARGET := $(shell exit -1)
Note again that this calls a shell that in turns runs the shell's exit built-in, i.e.: it does not exit make. The typical approach for exiting while processing a makefile is to call GNU Make's error built-in function instead:
$(error Error-message-here)
Putting everything together:
ifeq ($(ENVIRONMENT),LOCAL)
TARGET := local_target
else # indent with spaces, not a tab
$(error ENVIRONMENT not set to LOCAL)
endif

Using ifeq to test the variables

I tried to write this dynamic target to check the variable before running the actual target:
.PHONY: check-env-%
check-env-%:
ifeq ($(${*}),)
$(error not found ${*})
endif
so that I can use it like:
build: check-env-VERSION
But looks like it cannot compare it and even when I supply the required variable, it errors: Makefile:16: *** not found VERSION. Stop.
I believe I'm using the ifeq correctly but not sure why it cannot compare it?
From the docs: "Conditionals control what make actually “sees” in the makefile, so they cannot be used to control recipes at the time of execution." So your access to $* always yields an empty string at the time of makefile analysis, leaving your $(error) as recipe instruction.
Vroomfondel is right. What you can do instead is this:
check-env-%:
test $($*) || (echo $* not found; exit 1;)
...
test shall stop when there is no variable defined.

How to printout a value in a makefile

I have a make file that I want to debug. I have a construct such as follow:
ifeq ($(CC_VER),4.3)
error "I am here"
AR = ar6x qwe
CSL_LIBDIR = $(CC_DIR)\lib
CSL_INCDIR = $(CC_DIR)\include
else
error "Please check that commands and include/lib path are correct for your version of CC compiler"
endif
But it doesn't work. run this makefile from a batchfile which set the CC_Ver as follow:
set CC_VER= 4.3
I want to find a way to printout the CC_Ver so I can find why the if doesn't work.
Also how can I generate an error? The error "message" doesn't work.
I am using Gmake.
You can use the $(error text...) construct for the error. It generates a fatal error where the messsage is text as in:
$(error Please check that commands and include/lib path are correct for your version of CC compiler)
Similarly, you can use the $(info text...) construct for informational purposes, as in
$(info CC_VER has the value "$(CC_VER)")
See Functions That Control Make for the documentation.
If you are just looking to quickly inspect the value of a variable, you can also use the -p or --print-data-base option to make, which will print all rules and variable values.
The if statement fails because you have space between the = and 4.3 in the set CC_VER command. This space is preserved in your variable value, and consequently $(CC_VER) is not equal to 4.3, but to <space>4.3

Get exit code 1 on Makefile if statement

I'm trying to get the exit code on the ifdef statement if the statement is not true, but I tried by using exit 1 and $(call exit 1)
when using the first on the following code I get "Makefile:11: * missing separator. Stop."
...
ifdef PACKAGE
PACKAGEDIR = $(HOME)/$(PACKAGE)
else
exit 1
endif
...
By using $(call exit 1) I get no error but the makefile still keeps executing.
What I'm trying to accomplish is to exit the Makefile on the else with the error code 1
Thanks
As geekosaur says you can't put a shell command like exit 1 as a makefile operation. Makefiles are not shell scripts, although they can contain shell scripts. Shell commands can only appear within a target recipe, and nowhere else.
If you have a sufficiently new version of GNU make you can use the $(error ...) function, like this:
ifdef PACKAGE
PACKAGEDIR = $(HOME)/$(PACKAGE)
else
$(error You must define the PACKAGE variable)
endif
Also note that ifdef will be true if the variable is defined, even if it's defined to be the empty string. You may prefer:
ifneq ($(PACKAGE),)
PACKAGEDIR = $(HOME)/$(PACKAGE)
else
$(error You must define the PACKAGE variable)
endif
to ensure the variable is set to a non-empty value.
And, it's possible your version of GNU make is too old to support the $(error ...) function, although it's been around for a long time now.
You can't simply have bare code sticking somewhere in a Makefile; code (such as exit 1) is always associated with a build rule of some kind.
In this case you want the $(error) function. It may not be sufficient to drop it in the else, though, for the same reason that exit 1 itself won't work there; you may need to rephrase the whole thing as
PACKAGEDIR := $(if $(flavor PACKAGE),undefined,$(error PACKAGE must be defined!),$(HOME)/$(PACKAGE))

Resources