Stop executing makefile

2020-07-06 03:42发布

问题:

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"

回答1:

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.



回答2:

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


回答3:

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