How to pass argument to Makefile from command line?
Solution 1
You probably shouldn't do this; you're breaking the basic pattern of how Make works. But here it is:
action:
@echo action $(filter-out [email protected],$(MAKECMDGOALS))
%: # thanks to chakrit
@: # thanks to William Pursell
EDIT:
To explain the first command,
$(MAKECMDGOALS) is the list of "targets" spelled out on the command line, e.g. "action value1 value2".
[email protected] is an automatic variable for the name of the target of the rule, in this case "action".
filter-out is a function that removes some elements from a list. So $(filter-out bar, foo bar baz) returns foo baz (it can be more subtle, but we don't need subtlety here).
Put these together and $(filter-out [email protected],$(MAKECMDGOALS)) returns the list of targets specified on the command line other than "action", which might be "value1 value2".
Solution 2
Here is a generic working solution based on @Beta's
I'm using GNU Make 4.1 with SHELL=/bin/bash atop my Makefile, so YMMV!
This allows us to accept extra arguments (by doing nothing when we get a job that doesn't match, rather than throwing an error).
%:
@:
And this is a macro which gets the args for us:
args = `arg="$(filter-out [email protected],$(MAKECMDGOALS))" && echo $${arg:-${1}}`
Here is a job which might call this one:
test:
@echo $(call args,defaultstring)
The result would be:
$ make test
defaultstring
$ make test hi
hi
Note! You might be better off using a "Taskfile", which is a bash pattern that works similarly to make, only without the nuances of Maketools. See https://github.com/adriancooney/Taskfile
Solution 3
Much easier aproach. Consider a task:
provision:
ansible-playbook -vvvv \
-i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory \
--private-key=.vagrant/machines/default/virtualbox/private_key \
--start-at-task="$(AT)" \
-u vagrant playbook.yml
Now when I want to call it I just run something like:
AT="build assets" make provision
or just:
make provision in this case AT is an empty string
Solution 4
Few years later, want to suggest just for this: https://github.com/casey/just
action v1 v2=default:
@echo 'take action on {{v1}} and {{v2}}...'
Related videos on Youtube
Meng Lu
Updated on November 19, 2021Comments
-
Meng Lu about 1 yearHow to pass argument to Makefile from command line?
I understand I can do
$ make action VAR="value" $ valuewith
MakefileVAR = "default" action: @echo $(VAR)How do I get the following behavior?
$ make action value valueHow about
$make action value1 value2 value1 value2-
glerYbo about 7 yearsSimilar: Passing arguments to “make run” -
Lesmana over 5 yearsPossible duplicate of Passing arguments to "make run"
-
-
Evgeniy Generalov over 8 years
$(shell echo $(MAKECMDGOALS) | sed 's!^.* [email protected] !!')to omit all targets before and just consider the following as arguments:make target1 target2 action value1 value2 -
Jon about 8 yearsPardon my ignorance. I've tried googling%:and@:and cannot find info on what those "directives" (or whatever they're called) do. Could you please explain? -
Beta about 8 years@Jon: The manual is here. The part consisting of%:and@:is a rule. The target name%means that it is a rule that matches anything; that is, if Make can't find any other way to build the thing you tell it to build, it will execute that rule. The@:is a recipe; the:means do nothing, and the@means do it silently. -
Jon about 8 yearsThanks. I had been reading that manual and I didn't consider at first, that%:was actually% :, a wildcard type target name. I don't see anything in that manual page regarding@:though... it does suggest that a "do-nothing" rule would simply have a;after the target specification, so, would it not be more accurate to write% : ;as the "wildcard do-nothing" rule? -
Gingi over 7 yearsfilter-outdoesn't work when the action is a dependency of the target specified on the command line, because[email protected]will be set to the dependency's name, not the original argument called on the command line. Instead, I assignMAKECMDGOALSto a shell array and then remove the first element:@ args=($(MAKECMDGOALS)); args=("$${args[@]:1}") -
patcon over 6 yearsfwiw, ":" is a synonym of "true" command, which is likely less cryptic. ":" isn't used often anymore, and brevity likely isn't worth it...? -
Chris over 5 years@Beta using your solution (awesome, wow)--do you know how to suppress the output at the end of execution that says,make: 'input1' is up to datefor the various inputs? -
Sion over 4 years@Beta this got me 90% of the way but if my arg is "le creuset" it will split on the space despite being wrapped in ". Is there a known workaround here?
-
Abdullah Al Maruf - Tuhin almost 4 yearsIt worked!! TO other people trying it out, make sure there is
tabbefore@echo, notspace. -
SergiyKolesnikov about 2 yearsThis also works if the action (e.g., test:) is a dependency of the target specified on the command line. -
oz123 over 1 yearThis will execute the targethiif this target exist in the Makefile. Any idea how to avoid this? -
M3D over 1 year@oz123 You might want to look into using environment variables, rather than positional arguments. You could also look at using a scripting language for this. As mentioned, bash has some useful patterns for this.
-
Big McLargeHuge 9 months"you're breaking the basic pattern of how Make works" - what do you mean by this? And what is the "correct" pattern? -
abc123 7 monthsThis works for me but it outputsmake: *** No rule to make target 'value'. Stop.. How to prevent this?