Get exit code 1 on Makefile if statement - makefile

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

Related

Make: No main target

Is it possible to make make not have a main target, meaning that invocations to make without a specified target would fail, even if a first target exists?
Not specifically that, but if you are using GNU make there are ways to ensure users provide a goal on the command line.
First, you could check MAKECMDGOALS:
ifeq ($(MAKECMDGOALS),)
$(error Missing command line goal!)
endif
Or alternatively you could use .DEFAULT_GOAL to force the default goal to be a rule that fails:
.DEFAULT_GOAL = fail
fail:; #echo Missing command line goal; exit 1

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.

Changing value of a variable according to a condition inside a target in Makefile

In a makefile which I have ,I want to assign value to a variable based on a condition.
I have:
CMAKE=cmake ../
I tried doing:
if test condition;
then $(eval CMAKE := $(cmake -DCMAKE_BUILD_TYPE=Release ../));\
fi;
But this does not work.Is there any other way to do this?
P.S The error which is getting reported is :
Syntax error: ";" unexpected
When I removed ";" ,it showed another error :
Syntax error: "fi" unexpected
This kind of "back and forth" between the shell and make is not possible. It's important to understand the relationship between them: make does not implement a shell parser: it just runs the shell for that. All make gets back from the shell is a single exit code that determines whether the command succeeded or not.
Make runs a recipe by first expanding all the variables and functions in the recipe, then passing the resulting command to the shell to be invoked.
Thus it should be clear why your example doesn't work.
Before we can give you good advice we'd need higher-level information about exactly what you're trying to do and why. One way to do what you want is to use $(shell ...) to compute the conditional, all outside of any rule:
ifeq ($(shell test condition && echo true),true)
CMAKE := cmake -DCMAKE_BUILD_TYPE=Release ../
endif
However, this looks pretty strange to me. If you described what you really want to do we can probably give you better help.
ETA:
Based on your description below, the best option is target-specific variables:
CMAKE_BUILD_FLAG = -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
debug: CMAKE_BUILD_TYPE = Debug
release: CMAKE_BUILD_TYPE = Release
setup: CMAKE_BUILD_FLAG =
debug release setup: all
all:
cmake $(CMAKE_BUILD_FLAG) ../

Resources