web-dev-qa-db-fra.com

Tester si un fichier existe dans la cible du makefile et quitter s'il n'est pas présent

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?

22
Alex Reynolds

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; }
17
Olaf Dietsche

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
25
KingRadical

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; }
5
laindir

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.

1
Chen Levy

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
1
kenorb