Lazy Set
VARIABLE = value
Normal setting of a variable, but any other variables mentioned with the value
field are recursively expanded with their value at the point at which the variable is used, not the one it had when it was declared
Immediate Set
VARIABLE := value
Setting of a variable with simple expansion of the values inside - values within it are expanded at declaration time.
Lazy Set If Absent
VARIABLE ?= value
Setting of a variable only if it doesn't have a value. value
is always evaluated when VARIABLE
is accessed. It is equivalent to
ifeq ($(origin VARIABLE), undefined)
VARIABLE = value
endif
See the documentation for more details.
Append
VARIABLE += value
Appending the supplied value to the existing value (or setting to that value if the variable didn't exist)
It is actually executing the command, changing the directory to some_directory
, however, this is performed in a sub-process shell, and affects neither make nor the shell you're working from.
If you're looking to perform more tasks within some_directory
, you need to add a semi-colon and append the other commands as well. Note that you cannot use newlines as they are interpreted by make as the end of the rule, so any newlines you use for clarity needs to be escaped by a backslash.
For example:
all:
cd some_dir; echo "I'm in some_dir"; \
gcc -Wall -o myTest myTest.c
Note also that the semicolon is necessary between every command even though you add a backslash and a newline. This is due to the fact that the entire string is parsed as a single line by the shell. As noted in the comments, you should use '&&' to join commands, which mean they only get executed if the preceding command was successful.
all:
cd some_dir && echo "I'm in some_dir" && \
gcc -Wall -o myTest myTest.c
This is especially crucial when doing destructive work, such as clean-up, as you'll otherwise destroy the wrong stuff, should the cd
fail for whatever reason.
A common usage though is to call make in the sub directory, which you might want to look into. There's a command line option for this so you don't have to call cd
yourself, so your rule would look like this
all:
$(MAKE) -C some_dir all
which will change into some_dir
and execute the Makefile
in there with the target "all". As a best practice, use $(MAKE)
instead of calling make
directly, as it'll take care to call the right make instance (if you, for example, use a special make version for your build environment), as well as provide slightly different behavior when running using certain switches, such as -t
.
For the record, make always echos the command it executes (unless explicitly suppressed), even if it has no output, which is what you're seeing.
Best Answer
TL;DR: Use the
error
function:Note that the lines must not be indented. More precisely, no tabs must precede these lines.
Generic solution
In case you're going to test many variables, it's worth defining an auxiliary function for that:
And here is how to use it:
This would output an error like this:
Notes:
The real check is done here:
This reflects the behavior of the
ifndef
conditional, so that a variable defined to an empty value is also considered "undefined". But this is only true for simple variables and explicitly empty recursive variables:As suggested by @VictorSergienko in the comments, a slightly different behavior may be desired:
And:
Target-specific check
It is also possible to extend the solution so that one can require a variable only if a certain target is invoked.
$(call check_defined, ...)
from inside the recipeJust move the check into the recipe:
The leading
@
sign turns off command echoing and:
is the actual command, a shell no-op stub.Showing target name
The
check_defined
function can be improved to also output the target name (provided through the$@
variable):So that, now a failed check produces a nicely formatted output:
check-defined-MY_FLAG
special targetPersonally I would use the simple and straightforward solution above. However, for example, this answer suggests using a special target to perform the actual check. One could try to generalize that and define the target as an implicit pattern rule:
Usage:
Notice that the
check-defined-BAR
is listed as the order-only (|...
) prerequisite.Pros:
Cons:
make -t
(see Instead of Executing Recipes) will pollute your root directory with lots ofcheck-defined-...
files. This is a sad drawback of the fact that pattern rules can't be declared.PHONY
.I believe, these limitations can be overcome using some
eval
magic and secondary expansion hacks, although I'm not sure it's worth it.