I have some variables defined in my Makefile which I pass to a compiler when I need to build my software. However, I need to make sure that these variables satisfy certain boolean identities at the level of the Makefile. I am currently doing something like the following.
SHELL := /bin/bash
NUMBER := 1
all: test.x
%.x: %.c ASSERT
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@
ASSERT: Makefile
@if (( $(NUMBER) < 0 || $(NUMBER) > 4 )); then \
echo "ERROR: NUMBER must be positive and less than 4."; \
exit 1; \
fi
@echo "Ran ASSERT. No errors found."
The problem with the above setup is that it always runs the compilation recipe even if the target already exists and nothing has changed.
How can I run Makefile assertions properly so that targets are made only when there are changes in the Makefile variables?
You have said that all your object files depend on the prerequisite ASSERT
. That prerequisite does not exist, so make will try to create it. Once make tries to create it, it will be considered "very new" and so any target that depends on it will be considered out of date and rebuilt.
Then the next time make runs, it sees that the prerequisite ASSERT
does not exist, so it will try to create it and it will be considered "very new". Etc. etc.
If you don't want everything to be rebuilt, then your recipe for ASSERT
must create the file ASSERT
when it succeeds:
ASSERT: Makefile
@...
@touch $@
@echo "Ran ASSERT. No errors found."
Just remember that this won't have any impact if you run make NUMBER=10
rather than editing the makefile. Since the makefile isn't changed, ASSERT
won't be out of date and so its recipe won't be invoked.
ETA
If all you want to do is verify that no one can use a NUMBER
value that's illegal, ever, you can just test that directly with make rather than using a recipe to do it:
SHELL := /bin/bash
NUMBER := 1
$(if $(filter $(NUMBER), 0 1 2 3 4),\
$(info NUMBER is good),\
$(error ERROR: NUMBER must be positive and less than 4.))
all: test.x
%.x: %.c ASSERT
@echo "Compiling $< -> $@ with NUMBER=$(NUMBER)."
@gcc $< -D NUMBER=$(NUMBER) -o $@