2012-12-13 2 views
10

Voici une version réduite de mon Makefile:dépendances Makefile ne fonctionnent pas pour cible phony

.PHONY: all 

all: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Je veux courir make et ont seulement elle recompiler quand src/server.coffee a changé. Cependant, il recompile chaque fois que je lance make:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 

Si je change Makefile de ne pas utiliser une cible bidon, il fonctionne comme prévu. Nouveau Makefile:

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Résultat:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
make: `bin/server.js' is up to date. 

Pourquoi viendriez pas respecter mes dépendances avec une cible bidon? La raison pour laquelle je demande est parce qu'en réalité, je ne vais pas simplement compiler un seul fichier dans un seul autre fichier, donc je ne veux pas avoir à suivre les noms de tous les fichiers de sortie à utiliser comme cibles.

Répondre

8

Au lieu d'une cible factice (qui, comme @cmotley souligne, travaille exactement comme il se doit) ce que vous pouvez utiliser lorsque vous voulez éviter un travail supplémentaire est un "empty target":

La cible vide est un variante de la cible bidon; il est utilisé pour contenir des recettes pour une action que vous demandez explicitement de temps en temps. Contrairement à une cible bidon, ce fichier cible peut vraiment exister; mais le contenu du fichier n'a pas d'importance, et sont généralement vides.

Le but du fichier cible vide est d'enregistrer, avec l'heure de la dernière modification, le moment où la recette de la règle a été exécutée pour la dernière fois. Il le fait parce que l'une des commandes de la recette est une commande tactile pour mettre à jour le fichier cible.

Cependant, dans ce cas, il n'y a vraiment pas besoin d'ajouter un fichier de sortie vide supplémentaire - vous avez déjà la sortie de votre compilation CoffeeScript! Cela correspond au modèle Makefile plus typique, comme vous l'avez déjà démontré dans votre question. Ce que vous pouvez faire est refactor à cette approche:

.PHONY: all 
all: bin/server.js 

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Maintenant, vous avez deux choses: une belle cible « tout » classique qui est correctement mais faux ne fera pas un travail supplémentaire. Vous êtes également en meilleure position pour rendre plus générique afin que vous pouvez facilement ajouter d'autres fichiers:

.PHONY: all 
all: bin/server.js bin/other1.js bin/other2.js 

bin/%.js: src/%.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin $< 
+3

Juste pour être clair, une ** cible vide ** doit être un fichier et est vraiment juste utilisée pour son horodatage? Existe-t-il un autre type de '.PHONY 'qui permet à une règle cible d'avoir un corps de recette (avec des commandes qui sont exécutées) * et * ne s'exécute que lorsque les dépendances ont besoin d'être mises à jour? Il semble assez cassé car il faut que '.PHONY' fasse des choses différentes selon qu'il a un corps de recette ou non. – jozxyqk

4

Un fichier cible doit être comparé à l'heure de modification du fichier server.coffee. Puisque vous n'avez pas de cible concrète make ne peut pas savoir si la sortie est plus récente que la dépendance ou non, donc il va toujours construire all.

+0

Ah, merci. Je ne me suis pas rendu compte que c'était de savoir comment calculer quels fichiers devaient être recompilés. Très utile –

9

Selon la documentation Marque:

The prerequisites of the special target .PHONY are considered 
to be phony targets. When it is time to consider such a target, 
make will run its recipe unconditionally, regardless of whether 
a file with that name exists or what its last-modification time is. 

http://www.gnu.org/software/make/manual/html_node/Special-Targets.html

Faire court la recette des cibles PHONY sans conditions - conditions préalables ne sont pas importants.

+0

D'accord, c'est assez simple. Connaissez-vous une solution de contournement pour atteindre l'objectif de ne pas avoir à déclarer explicitement les fichiers de sortie qui dépendent d'un ensemble de fichiers source? –

+0

Vous pouvez déclarer certaines variables pour suivre les fichiers sources et les fichiers objets. Par exemple, SRC = $ (joker ./src/*.c) et OBJECTS = $ (patsubst% .c,% .o, $ (SRC)). Ensuite, $ (OBJETS) peut être une condition préalable pour votre cible. Je pense que c'est ce que vous essayez de faire. – cmotley

1

Comme les autres mentionnés, faire se penche sur les horodateurs des fichiers à savoir si les dépendances ont changé.

Si vous voulez "émuler" une fausse cible avec des dépendances, vous devrez créer un vrai fichier avec ce nom et utiliser la commande touch (sur les systèmes Unix).

J'avais besoin d'une solution pour nettoyer uniquement le répertoire si les fichiers makefiles étaient modifiés (c'est-à-dire que les drapeaux du compilateur étaient changés, donc les fichiers objets devaient être recompilés).

Voici ce que je (et exécute avant chaque compilation) avec un fichier nommé makefile_clean:

makefile_clean: makefile 
    @rm '*.o' 
    @sudo touch makefile_clean 

La commande touch met à jour l'horodatage de la dernière modification à l'heure actuelle.

Questions connexes