makefile exécute une autre cible

123

J'ai un makefile structuré quelque chose comme ceci:

all : 
    compile executable

clean :
    rm -f *.o $(EXEC)

J'ai réalisé que j'exécutais constamment "make clean" suivi de "clear" dans mon terminal avant de lancer "make all". J'aime avoir un terminal propre avant d'essayer de passer au crible les mauvaises erreurs de compilation C ++. J'ai donc essayé d'ajouter une troisième cible:

fresh :
    rm -f *.o $(EXEC)
    clear
    make all

Cela fonctionne, mais cela exécute une deuxième instance de make (je crois). Existe-t-il un bon moyen d'obtenir les mêmes fonctionnalités sans exécuter une deuxième instance de make?

sas4740
la source

Réponses:

172

En fait, vous avez raison: il exécute une autre instance de make. Une solution possible serait:

.PHONY : clearscr fresh clean all

all :
    compile executable

clean :
    rm -f *.o $(EXEC)

fresh : clean clearscr all

clearscr:
    clear

En appelant, make freshvous obtenez d'abord la cleancible, puis celle clearscreenqui s'exécute clearet enfin celle allqui fait le travail.

EDIT 4 août

Que se passe-t-il dans le cas de builds parallèles avec l' -joption make ? Il existe un moyen de régler la commande. À partir du manuel de fabrication, section 4.2:

Parfois, cependant, vous avez une situation où vous souhaitez imposer un ordre spécifique aux règles à appeler sans forcer la mise à jour de la cible si l'une de ces règles est exécutée. Dans ce cas, vous souhaitez définir des conditions préalables à la commande uniquement. Les prérequis de commande uniquement peuvent être spécifiés en plaçant un symbole de tuyau (|) dans la liste des prérequis: tous les prérequis à gauche du symbole de tuyau sont normaux; tous les prérequis à droite sont d'ordre uniquement: cibles: prérequis normaux | conditions préalables à la commande uniquement

La section des prérequis normaux peut bien sûr être vide. De plus, vous pouvez toujours déclarer plusieurs lignes de prérequis pour la même cible: elles sont ajoutées de manière appropriée. Notez que si vous déclarez que le même fichier est à la fois un prérequis normal et un prérequis de commande uniquement, le prérequis normal a la priorité (car il s'agit d'un sur-ensemble strict du comportement d'un prérequis de commande uniquement).

D'où le makefile devient

.PHONY : clearscr fresh clean all

all :
    compile executable

clean :
    rm -f *.o $(EXEC)

fresh : | clean clearscr all

clearscr:
    clear

EDIT 5 déc.

Ce n'est pas grave d'exécuter plus d'une instance de makefile puisque chaque commande à l'intérieur de la tâche sera de toute façon un sous-shell . Mais vous pouvez avoir des méthodes réutilisables en utilisant la fonction d'appel .

log_success = (echo "\x1B[32m>> $1\x1B[39m")
log_error = (>&2 echo "\x1B[31m>> $1\x1B[39m" && exit 1)

install:
  @[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
  command1  # this line will be a subshell
  command2  # this line will be another subshell
  @command3  # Use `@` to hide the command line
  $(call log_error, "It works, yey!")

uninstall:
  @[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
  ....
  $(call log_error, "Nuked!")
Dacav
la source
6
@ sas4740: fondamentalement, tout ce qui suit .PHONY : est traité comme un mot-clé qui est toujours exécuté, tandis que les cibles non fausses sont destinées à être des fichiers.
Dacav
Les "conditions préalables à la commande uniquement" sont-elles conditionnelles? pour la cible t2, je veux d'abord faire t0, que seulement si t0 réussit exécuter t1, et seulement si les deux réussissent exécuter une tâche dans t3
fantastique
1
@fantastory, non, je pense qu'ils sont indépendants. t2dépendra de t0, t1et t3. Si vous en avez besoin, vous devez le mettre t3comme requis par t2, t1comme requis par t3et t0comme requis par t1. Cela signifie 3 règles différentes. Vous devez cependant vérifier cela. Je ne suis pas sûr à 100%.
Dacav
3
"Les conditions préalables à la commande uniquement" sont indépendantes
fantastique
2
Je ne vois pas où est la garantie que «nettoyer» fonctionne avant «tout»? Le fait que vous les ayez corrigés | ne les fait pas exécuter dans l'ordre. La dépendance d'ordre uniquement signifie que la cible n'est pas nécessairement mise à jour après une telle opération. Cela n'a rien à voir avec l'ordre des éléments dépendants ... ou?
CygnusX1
6

Si vous avez supprimé la make allligne de votre "nouvelle" cible:

fresh :
    rm -f *.o $(EXEC)
    clear

Vous pouvez simplement exécuter la commande make fresh all, qui s'exécutera en tant que make fresh; make all.

Certains pourraient considérer cela comme une deuxième instance de make, mais ce n'est certainement pas une sous-instance de make (un make à l'intérieur d'un make), ce que votre tentative semble aboutir.

codenaugh
la source