I implement a recipe in order to pass all the remaining string to the command, as example in this script:
Makefile
run:
# ./bin/run.sh $(filter-out $@,$(MAKECMDGOALS))
@echo $(filter-out $@,$(MAKECMDGOALS))
But when I run as example:
>make run my custom input params
my custom input params
make: *** No rule to make target `my'. Stop.
makefile try to execute also the remaining string so the error:
make: *** No rule to make target `my'. Stop.
How can I prevent this?
NB: As workaround I define a dummy recipe:
%:
@echo
So this will print an empty string instead of the error.
I want to avoid to do something like:
make run-example param="my custom param"
I don't think you should use a Makefile. You want to do your own parsing of the options, and that's more trouble to do in make.
If you're dead set on it, you could do this:
%:
@true
...which will avoid printing an empty line.
It would be better to do this in Bash, though. Here's one way you could do it:
#!/usr/bin/env bash
if [ $# -lt 1 ]; then
echo Not enough args
exit 1
fi
case "$1" in
"run")
shift
./bin/run.sh $@
;;
*)
echo "Command $1 not recognized"
exit 1
;;
esac
This seems easier and more extensible.
You can probably achieve what you want with a match-anything rule. Example (using a dummy printf
recipe instead of a real one):
PARAMS := $(filter-out run,$(MAKECMDGOALS))
run:
@printf './bin/run.sh $(PARAMS)\n'
%:;
Demo:
$ make run my custom input params
./bin/run.sh my custom input params
make: 'my' is up to date.
make: 'custom' is up to date.
make: 'input' is up to date.
make: 'params' is up to date.
You can ignore the make: 'target' is up to date.
messages or use the --quiet
option (or --silent
or -s
):
$ make --quiet run my custom input params
./bin/run.sh my custom input params
If your Makefile is more complex than this, the match-anything rule could be a problem because it could catch other targets that you do not want to be caught. In this case make conditionals are an option:
ifeq ($(SECONDPASS),)
PARAMS := $(filter-out run,$(MAKECMDGOALS))
run:
@$(MAKE) --quiet $@ PARAMS='$(PARAMS)' SECONDPASS=true
%:;
else
run:
@printf './bin/run.sh $(PARAMS)\n'
# other rules if any
endif
Finally, if the name of the first goal is not always the same, you can adapt this with:
GOAL := $(firstword $(MAKECMDGOALS))
PARAMS := $(filter-out $(GOAL),$(MAKECMDGOALS))
$(GOAL):
@printf './bin/$(GOAL).sh $(PARAMS)\n'
%:;
Or:
GOAL := $(firstword $(MAKECMDGOALS))
ifeq ($(SECONDPASS),)
PARAMS := $(filter-out $(GOAL),$(MAKECMDGOALS))
$(GOAL):
@$(MAKE) --quiet $@ PARAMS='$(PARAMS)' SECONDPASS=true
%:;
else
$(GOAL):
@printf './bin/$(GOAL).sh $(PARAMS)\n'
# other rules if any
endif
Demo:
$ make --quiet nur foo bar
./bin/nur.sh foo bar
You can always pass / set ENV variables before executing make if you only want to pass variables to make or to a shell script.
MYPARAM1=123 MYPARAM2=456 make
OR using a subshell
(MYPARAM1=123; MYPARAM2=456; echo A=$MYPARAM1 B=$MYPARAM2; make)
(export MYPARAM1=123; export MYPARAM2=456; A=$MYPARAM1 B=$MYPARAM2; make) // exporting
You might also look at the bash-shell-special-parameters