Est-il possible de quitter avec une condition d'erreur si un fichier n'existe pas? Je suis en train de faire quelque chose comme ça:
all: foo
foo:
test -s /opt/local/bin/gsort || echo "GNU sort does not exist! Exiting..." && exit
L'exécution de make
exécute la cible all
, qui exécute foo
.
En principe, si la condition test -s
échoue, les instructions echo/exit
sont exécutées.
Cependant, même si /usr/bin/gsort
existe, j'obtiens le résultat de l'instruction echo
mais la commande exit
ne s'exécute pas. C'est le contraire de ce que j'espère accomplir.
Quelle est la bonne façon de faire quelque chose comme ci-dessus?
exit
alone renvoie le statut de la dernière commande exécutée. Dans ce cas, il renvoie zéro, ce qui signifie que tout va bien.
En effet, ||
et &&
ont une priorité égale , et le shell interprète la commande comme si elle était écrite.
( test ... || echo ... ) && exit
Si vous souhaitez signaler une défaillance, vous devez quitter avec une valeur non nulle, par exemple. exit 1
. Et si vous voulez utiliser echo et exit, il suffit de mettre les commandes en séquence en les séparant par ;
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
Je réalise que c'est un peu vieux à ce stade, mais vous n'avez même pas besoin d'utiliser un sous-shell pour vérifier si un fichier existe dans Make.
Cela dépend aussi de la façon dont vous voulez/attendez que cela fonctionne.
En utilisant la fonction générique, comme ceci:
all: foo
foo:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
est un bon moyen de le faire. Notez ici que la clause ifeq n’est pas mise en retrait car elle est évaluée avant la cible elle-même.
Si vous voulez que cela se produise inconditionnellement pour chaque cible, vous pouvez simplement la déplacer en dehors de la cible:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
Chaque ligne de commande de make est exécutée dans son propre sous-shell. Donc, exécuter exit
quitte simplement ce sous-shell - pas le fichier Make dans son ensemble. Par défaut, l'exécution de make
sera arrêtée si un sous-shell renvoie un statut de sortie non réussi (par convention, 0 signifie succès, ainsi tout ce qui va arrêter l'exécution). La méthode la plus simple consisterait simplement à utiliser le statut de sortie de la commande test
:
all: foo
foo:
test -s /opt/local/bin/gsort
L'impression d'un message de diagnostic complique légèrement les choses car des commandes telles que echo
renverront un état de sortie de 0, ce qui fera penser que make
ira bien. Pour contourner ce problème, vous devez exécuter une commande après qui donnera au sous-shell un statut de sortie non nul:
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
ou même juste
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; false; }
Faites simplement:
all: /opt/local/bin/gsort
et si /opt/local/bin/gsort
est manquant, vous obtiendrez un message d'erreur "pas de règle pour rendre la cible`/opt/local/bin/gsort '"cible.
Mais si vous voulez aussi des explications intéressantes, faites-le:
/opt/local/bin/gsort:
echo "GNU sort does not exist! Exiting..."
false
Dans GNU/Make, si la cible n’est pas déclarée .PHONEY
et n’a pas de dépendances, la règle sera invoquée si un fichier correspondant à cette cible n’existe pas.
Le code ci-dessus déclenche la commande false
uniquement lorsque /opt/local/bin/gsort
n'existe pas, renvoie une valeur autre que 0 et échoue.
Puisque vous vérifiez si le fichier exécutable gsort
existe, vous pouvez utiliser la commande Shell which
ou type
pour, par exemple:
all: foo
:
foo:
which gsort || exit 1
# or
type gsort || exit 1
Vous n'avez pas besoin d'un message d'erreur, car il va automatiquement imprimer:
/ bin/sh: ligne 0: type:
gsort
: non trouvé
ce qui est évident.
Vous pouvez également utiliser test
ou [
(voir: help test
/help [
pour la syntaxe), par exemple.
test -x /opt/local/bin/gsort || { echo Error msg; exit 1; }
qui vérifie si le fichier donné existe et qu'il est exécutable, sinon affiche le message et quitte. Les parenthèses sont importantes pour remplacer la priorité normale des opérateurs (de gauche à droite) en regroupant les commandes (voir la section Compound Commands
dans man bash
pour plus d'informations).
Une autre méthode consiste à utiliser les cibles de la règle pour vérifier si le fichier existe et à ajouter une dépendance à all
, par exemple.
all: /opt/local/bin/gsort
@echo Success.
/opt/local/bin/gsort:
@echo "GNU sort does not exist! Exiting..."
exit 1
Résultat:
$ make
GNU sort does not exist! Exiting...
exit 1
make: *** [/opt/local/bin/gsort] Error 1