Makefile passing additional arguments to targets command from make command

Viewed 13158

I have a Makefile that defines docker-compose project. It essentially assembles me a command:

COMMAND := docker-compose --project-name=$(PREFIX) --file=$(FILE_PATH)

up:
    $(COMMAND) up -d

I would like to add a target named dc to which I would be able to pass any arguments I want.

I know there is one solution:

target:
    $(COMMAND) $(ARGS)

And then call it with make target ARGS="--help" for example.

But isn't there an easier way like in bash $@ ? I would like to skip the ARGS=... part and send everything to the command after target name.

3 Answers

Not really. The make program interprets all arguments (that don't contain =) as target names to be built and there's no way you can override that. So even though you can obtain the list of arguments given on the command line (via the GNU make-specific $(MAKECMDGOALS) variable) you can't prevent those arguments from being considered targets.

You could do something like this, which is incredibly hacky:

KNOWN_TARGETS = target

ARGS := $(filter-out $(KNOWN_TARGETS),$(MAKECMDGOALS))

.DEFAULT: ;: do nothing

.SUFFIXES:
target:
        $(COMMAND) $(ARGS)

(untested). The problem here is you have to keep KNOWN_TARGETS up to date with all the "real" targets so you can remove them from the list of targets given on the command line. Then add the .DEFAULT target which will be run for any target make doesn't know how to build, which does nothing. Reset the .SUFFIXES meta-target to remove built-in rules.

I suspect this still will have weird edge-cases where it doesn't work.

Also note you can't just add options like --help to the make command line, because make will interpret them itself. You'll have to prefix them with -- to force make to ignore them:

make target -- --help

Another option would be to add a target like this:

target%:
        $(COMMAND) $*

Then you can run this:

make "target --help"

But you have to include the quotes.

In general I just recommend you reconsider what you want to do.

You could write a bash wrapper script to do what you'd like:

#/bin/bash
make target ARGS=\"$@\"

The reason you don't want to do it in make, is that make parses the command line parameters before it parse the makefile itself, so by the time you read the makefile, the targets, variables, etc have already been set. This means that make will have already interpreted the extra parameters as new targets, variables etc.

The first answer is correct, no passthru of args. However, here is a plausible path for experimentation, use of branch by include selection:

# Makefile:

COMMAND := $(PYTHON) this_shit_got_real.py
LOCAL_MK ?= local.mk

# '-' important, absence of LOCAL_MK is not cause for error, just run with no overrides
- include $(LOCAL_MK)

target:
  $(COMMAND) $(ARGS)

Now see how you add branching with env:

echo "ARGS=--help">>local.mk
# make target

And the other cli controlled branch

echo "ARGS=--doit">>runner.mk
# LOCAL_MK=runner.mk make target
Related