Comment passer l'argument à Makefile à partir de la ligne de commande?

109

Comment passer l'argument à Makefile à partir de la ligne de commande?

Je comprends que je peux faire

$ make action VAR="value"
$ value

avec Makefile

VAR = "default"
action:
    @echo $(VAR)

Comment obtenir le comportement suivant?

$ make action value
value

?

Que diriez-vous

$make action value1 value2
value1 value2
Meng Lu
la source
3
Possible duplication de Passing arguments to "make run"
lesmana

Réponses:

212

Vous ne devriez probablement pas faire cela; vous cassez le schéma de base du fonctionnement de Make. Mais voici:

action:
        @echo action $(filter-out $@,$(MAKECMDGOALS))

%:      # thanks to chakrit
    @:    # thanks to William Pursell

EDIT:
Pour expliquer la première commande,

$(MAKECMDGOALS) est la liste des "cibles" énoncées sur la ligne de commande, par exemple "action value1 value2".

$@est une variable automatique pour le nom de la cible de la règle, dans ce cas "action".

filter-outest une fonction qui supprime certains éléments d'une liste. Donc $(filter-out bar, foo bar baz)revient foo baz(ça peut être plus subtil, mais on n'a pas besoin de subtilité ici).

Mettez-les ensemble et $(filter-out $@,$(MAKECMDGOALS))renvoie la liste des cibles spécifiées sur la ligne de commande autre que "action", qui peut être "valeur1 valeur2".

Bêta
la source
1
$(shell echo $(MAKECMDGOALS) | sed 's!^.* $@ !!')d'omettre toutes les cibles avant et de considérer simplement ce qui suit comme arguments:make target1 target2 action value1 value2
Evgeniy Generalov
1
Pardonnez mon ignorance. J'ai essayé de googler %:et je @:ne trouve pas d'informations sur ce que font ces "directives" (ou ce qu'elles appellent). Pouvez-vous expliquer?
Jon
15
@Jon: Le manuel est ici . La partie constituée de %:et @:est une règle . Le nom de la cible %signifie qu'il s'agit d' une règle qui correspond à tout ; c'est-à-dire que si Make ne trouve aucun autre moyen de construire l'objet que vous lui dites de construire, il exécutera cette règle. Le @:est une recette ; les :moyens ne font rien, et les @moyens le font en silence.
Bêta le
Merci. J'avais lu ce manuel et je n'avais pas envisagé au début, %:c'était en fait % :un nom de cible de type générique. Je ne vois rien dans cette page de manuel concernant @:cependant ... cela suggère qu'une règle "ne rien faire" aurait simplement un ;après la spécification cible, alors, ne serait-il pas plus précis d'écrire % : ;comme le font le caractère générique -aucune règle "?
Jon
1
filter-outne fonctionne pas lorsque l'action est une dépendance de la cible spécifiée sur la ligne de commande, car $@elle sera définie sur le nom de la dépendance, et non sur l'argument d'origine appelé sur la ligne de commande. Au lieu de cela, j'assigne MAKECMDGOALSà un tableau de shell puis supprime le premier élément:@ args=($(MAKECMDGOALS)); args=("$${args[@]:1}")
Gingi
18

Voici une solution de travail générique basée sur @ Beta

J'utilise GNU Make 4.1 avec SHELL=/bin/bashau sommet de mon Makefile, donc YMMV!

Cela nous permet d'accepter des arguments supplémentaires (en ne faisant rien lorsque nous obtenons un travail qui ne correspond pas, plutôt que de lancer une erreur).

%:
    @:

Et c'est une macro qui obtient les arguments pour nous:

args = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $${arg:-${1}}`

Voici un travail qui pourrait appeler celui-ci:

test:
    @echo $(call args,defaultstring)

Le résultat serait:

$ make test
defaultstring
$ make test hi
hi

Remarque! Vous feriez peut-être mieux d'utiliser un "Taskfile", qui est un modèle bash qui fonctionne de la même manière, mais sans les nuances de Maketools. Voir https://github.com/adriancooney/Taskfile

M3D
la source
Ça a marché!! À d'autres personnes qui l'essaient, assurez-vous qu'il y en a tabavant @echo, non space.
Abdullah Al Maruf - Tuhin
11

Approche beaucoup plus facile. Considérez une tâche:

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

Maintenant, quand je veux l'appeler, je lance juste quelque chose comme:

AT="build assets" make provision

ou juste:

make provisiondans ce cas ATest une chaîne vide

Kharandziuk
la source
-2

n'essaye pas de faire ça

$ make action value1 value2

créez plutôt un script:

#! /bin/sh
# rebuild if necessary
make
# do action with arguments
action "$@"

et faites ceci:

$ ./buildthenaction.sh value1 value2

pour plus d'explications sur pourquoi cela et les mises en garde concernant le piratage de makefile, lisez ma réponse à une autre question très similaire mais apparemment pas dupliquée: Passer des arguments pour "faire fonctionner"

lesmana
la source