Dans un Makefile, une deploy
recette a besoin d'une variable d'environnement ENV
à définir pour s'exécuter correctement, alors que d'autres s'en moquent, par exemple:
ENV =
.PHONY: deploy hello
deploy:
rsync . $(ENV).example.com:/var/www/myapp/
hello:
echo "I don't care about ENV, just saying hello!"
Comment puis-je m'assurer que cette variable est définie, par exemple: existe-t-il un moyen de déclarer cette variable makefile comme prérequis de la recette de déploiement, comme:
deploy: make-sure-ENV-variable-is-set
?
Je vous remercie.
make
il le définir, ou donner un avertissement ou générer une erreur fatale?make ENV=dev
mais s'il l'oublieENV=dev
, ladeploy
recette échouera ...Réponses:
Cela causera une erreur fatale si elle
ENV
n'est pas définie et que quelque chose en a besoin (dans GNUMake, de toute façon).(Notez que ifndef et endif ne sont pas indentés - ils contrôlent ce que make "voit" , prenant effet avant l'exécution du Makefile. "$ (Error" est indenté avec une tabulation de sorte qu'il ne s'exécute que dans le contexte de la règle.)
la source
ENV is undefined
lors de l'exécution d'une tâche qui n'a pas check-env comme prérequis.check-env
règle; Make ne le développera pas tant que / jusqu'à l'exécution de la règle. S'il ne commence pas par un TAB (comme dans l'exemple de @ rane), Make l'interprète comme n'étant pas dans une règle, et l'évalue avant d'exécuter une règle, quelle que soit la cible.Vous pouvez créer une cible de garde implicite, qui vérifie que la variable dans le radical est définie, comme ceci:
Vous ajoutez ensuite une
guard-ENVVAR
cible partout où vous souhaitez affirmer qu'une variable est définie, comme ceci:Si vous appelez
make change-hostname
, sans ajouterHOSTNAME=somehostname
l'appel, vous obtiendrez une erreur et la construction échouera.la source
if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi
DVariante en ligne
Dans mes makefiles, j'utilise normalement une expression comme:
Les raisons:
N'oubliez pas le commentaire qui est important pour le débogage:
... vous oblige à rechercher le Makefile pendant que ...
... explique directement ce qui ne va pas
Variante globale (par souci d'exhaustivité, mais non demandée)
En plus de votre Makefile, vous pouvez également écrire:
Avertissements:
clean
cible échouera si ENV n'est pas défini. Sinon, voyez la réponse de Hudon qui est plus complexela source
@
. -> gnu.org/software/make/manual/make.html#Echoing@test -n "$(name)" || (echo 'A name must be defined for the backup. Ex: make backup name=xyz' && exit 1)
Un problème possible avec les réponses données jusqu'à présent est que l'ordre des dépendances dans make n'est pas défini. Par exemple, exécuter:
quand
target
a quelques dépendances ne garantit pas que celles-ci s'exécuteront dans un ordre donné.La solution pour cela (pour garantir que ENV sera vérifié avant que les recettes ne soient choisies) est de vérifier ENV lors du premier passage de make, en dehors de toute recette:
Vous pouvez lire sur les différentes fonctions / variables utilisées ici et
$()
c'est juste un moyen de déclarer explicitement que nous comparons avec "rien".la source
J'ai trouvé que la meilleure réponse ne peut pas être utilisée comme une exigence, sauf pour les autres cibles PHONY. S'il est utilisé comme dépendance pour une cible qui est un fichier réel, l'utilisation
check-env
forcera cette cible de fichier à être reconstruite.D'autres réponses sont globales (par exemple, la variable est requise pour toutes les cibles dans le Makefile) ou utilisent le shell, par exemple si ENV manquait, make se terminerait indépendamment de la cible.
Une solution que j'ai trouvée aux deux problèmes est
La sortie ressemble à
value
a quelques mises en garde effrayantes, mais pour cette utilisation simple, je pense que c'est le meilleur choix.la source
Comme je le vois, la commande elle-même a besoin de la variable ENV afin que vous puissiez la vérifier dans la commande elle-même:
la source
deploy
n'est pas nécessairement la seule recette qui a besoin de cette variable. Avec cette solution, je dois tester l'état deENV
pour chacun d'entre eux ... alors que j'aurais aimé le traiter comme une seule (sorte de) condition préalable.Je sais que c'est vieux, mais j'ai pensé que je ferais écho à mes propres expériences pour les futurs visiteurs, car c'est un peu plus soigné à mon humble avis.
En règle générale,
make
utiliserash
comme shell par défaut ( défini via laSHELL
variable spéciale ). Danssh
et ses dérivés, il est trivial de quitter avec un message d'erreur lors de la récupération d'une variable d'environnement si elle n'est pas définie ou nulle en faisant:${VAR?Variable VAR was not set or null}
.En prolongeant cela, nous pouvons écrire une cible de création réutilisable qui peut être utilisée pour faire échouer d'autres cibles si une variable d'environnement n'a pas été définie:
Choses à noter:
$$
) est nécessaire pour reporter l'expansion vers le shell au lieu de l'intérieurmake
test
est juste pour empêcher le shell d'essayer d'exécuter le contenu deVAR
(cela ne sert à rien d'autre).check-env-vars
peut être étendu de manière triviale pour rechercher plus de variables d'environnement, chacune n'ajoutant qu'une seule ligne (par exemple@test $${NEWENV?Please set environment variable NEWENV}
)la source
ENV
contient des espaces, cela semble échouer (pour moi au moins)Vous pouvez utiliser à la
ifdef
place d'une cible différente.la source
deploy
n'est pas la seule recette à vérifier laENV
variable d'état..PHONY: deploy
etdeploy:
avant le bloc ifdef et supprimez la duplication. (btw j'ai édité la réponse pour refléter la bonne méthode)