I have the following in my makefile. Its a GNUmakefile
, so the additional make features are supported:
# Undefined Behavior Sanitzier (Clang and G++)
ifeq ($(findstring ubsan,$(MAKECMDGOALS)),ubsan)
CXXFLAGS += -fsanitize=undefined
MAKECMDGOALS := $(subst ubsan,,$(MAKECMDGOALS))
endif # UBsan
Running it results in:
make ubsan
make: *** No rule to make target 'ubsan'. Stop.
I know the code path is being executed (by introducing an error in the block). How do I remove the target from the command goals?
By default, the goal is the first target in the makefile (not counting targets that start with a period). Therefore, makefiles are usually written so that the first target is for compiling the entire program or programs they describe.
$@ is the name of the target being generated, and $< the first prerequisite (usually a source file). You can find a list of all these special variables in the GNU Make manual.
MAKECMDGOALS. The targets given to make on the command line. Setting this variable has no effect on the operation of make. See Arguments to Specify the Goals.
A simple makefile consists of "rules" with the following shape: target ... : dependencies ... command ... ... A target is usually the name of a file that is generated by a program; examples of targets are executable or object files.
You cannot do what you want here as far as I know.
You can modify the variable value and you will see the changes if you check the value yourself but modifying the value of MAKECMDGOALS
will not affect make in any way.
If you look at Appendix A Quick Reference in the GNU Make Manual you will see that it says:
MAKECMDGOALS
The targets given to make on the command line. Setting this variable has no effect on the operation of make.
See Arguments to Specify the Goals.
The closest you could get to what you are trying to do here, I think, would be to re-execute make on the Makefile
(or whatever) manually.
That being said this sort of thing is probably better done as variables instead of targets.
$ cat Makefile
$(info $(origin UBSAN))
$ make
undefined
$ make UBSAN=
command line
So something like this.
# Undefined Behavior Sanitzier (Clang and G++)
ifneq (undefined,$(origin UBSAN))
CXXFLAGS += -fsanitize=undefined
endif # UBsan
Yes, you can. Based on my recent answer to this other question Force Makefile to execute script after building any target (just before exiting), it was very easy to do what you would like.
This has only a drawback, you will lose any command-line arguments you pass directly to make as make all --silent
. However, you can look into the question: How to detect if the makefile `--silent/--quiet` command line option was set?, and recapture the command-line arguments you would like to repass to the second make call command on make -f ${MAKEFILE_JUSTNAME} ${MAKECMDGOALS}
.
ECHOCMD:=/bin/echo -e
SHELL := /bin/bash
ifeq (${IS_MAKEFILE_RUNNING_TARGETS},)
MAKEFILE_JUSTNAME := $(firstword ${MAKEFILE_LIST})
# UBsan
ifeq ($(findstring ubsan,${MAKECMDGOALS}),ubsan)
MAKECMDGOALS := $(subst ubsan,,${MAKECMDGOALS})
USELESS := $(eval export IS_UBSAN_CXXFLAGS_SET=1)
endif
define DEFAULTTARGET :=
printf 'Calling "%s" "%s"\n\n' "${MAKEFILE_JUSTNAME}" "${MAKECMDGOALS}"
make -f ${MAKEFILE_JUSTNAME} ${MAKECMDGOALS}
printf '\n'
printf 'Running something after all rules finished\n'
endef
%:
@:
# printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"
$(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
$(eval export IS_MAKEFILE_RUNNING_TARGETS=1)
all:
@:
# printf 'IS_MAKEFILE_RUNNING_TARGETS="%s"\n' "${IS_MAKEFILE_RUNNING_TARGETS}"
$(if ${IS_MAKEFILE_RUNNING_TARGETS},,${DEFAULTTARGET})
$(eval export IS_MAKEFILE_RUNNING_TARGETS=1)
else
# UBsan
ifneq (${IS_UBSAN_CXXFLAGS_SET},)
CXXFLAGS += -fsanitize=undefined
endif
all:
printf 'Calling my all rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
foo:
printf 'Calling my foo rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
bar:
printf 'Calling my bar rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
xyzzy:
printf 'Calling my xyzzy rule, CXXFLAGS="%s"\n' "${CXXFLAGS}"
endif
Usage examples:
make
printf 'Calling "%s" "%s"\n\n' "Makefile" ""
Calling "Makefile" ""
make -f Makefile
make[1]: Entering directory '/cygdrive/d/User/Downloads'
printf 'Calling my all rule, CXXFLAGS="%s"\n' ""
Calling my all rule, CXXFLAGS=""
make[1]: Leaving directory '/cygdrive/d/User/Downloads'
printf '\n'
printf 'Running something after all rules finished\n'
Running something after all rules finished
make foo bar
printf 'Calling "%s" "%s"\n\n' "Makefile" "foo bar"
Calling "Makefile" "foo bar"
make -f Makefile foo bar
make[1]: Entering directory '/cygdrive/d/User/Downloads'
printf 'Calling my foo rule, CXXFLAGS="%s"\n' ""
Calling my foo rule, CXXFLAGS=""
printf 'Calling my bar rule, CXXFLAGS="%s"\n' ""
Calling my bar rule, CXXFLAGS=""
make[1]: Leaving directory '/cygdrive/d/User/Downloads'
printf '\n'
printf 'Running something after all rules finished\n'
Running something after all rules finished
make foo bar ubsan
printf 'Calling "%s" "%s"\n\n' "Makefile" "foo bar "
Calling "Makefile" "foo bar "
make -f Makefile foo bar
make[1]: Entering directory '/cygdrive/d/User/Downloads'
printf 'Calling my foo rule, CXXFLAGS="%s"\n' "-fsanitize=undefined"
Calling my foo rule, CXXFLAGS="-fsanitize=undefined"
printf 'Calling my bar rule, CXXFLAGS="%s"\n' "-fsanitize=undefined"
Calling my bar rule, CXXFLAGS="-fsanitize=undefined"
make[1]: Leaving directory '/cygdrive/d/User/Downloads'
printf '\n'
printf 'Running something after all rules finished\n'
Running something after all rules finished
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With