2017-06-06 1 views
1

Le fichier Makefile ci-dessous doit créer (plusieurs) répertoires de sortie et générer une sortie dans ces répertoires, à partir de l'entrée dans le répertoire ci-dessus. Ainsi, lors de l'entrée, le répertoire n existe et le répertoire n /file.foo existe. La construction doit créer le répertoire n /out/file.bar.Erreur d'ordre de dépendance pour la création de plusieurs travaux

Ce Makefile fonctionne lorsqu'il est exécuté en tant que travail unique (notez qu'il crée les deux répertoires et fichiers source requis dans $(shell)). Il fonctionne probablement parce que makedirs est le premier/le plus à gauche prérequis pour all. Cependant, cela ne fonctionne pas pour une marque multi-tâches (c'est-à-dire make -j4/peu importe).

Des idées sur la façon de réparer les dépendances pour s'assurer que les répertoires de sortie sont créés avant d'être requis?

EDIT

Je aurais dû préciser que je l'ai essayé différentes pour commander seulement des solutions préalables, mais je ne pouvais le faire et de garantir que l'objectif effectivement reconstruit (le point de l'ordre seulement est généralement à empêcher la reconstruction, ne pas appliquer l'ordre de dépendance). Si vous avez une solution OO, veuillez la vérifier! Merci.

# expected output: 
# made directories 
# copying dir1/out/../file.foo to dir1/out/file.bar 
# copying dir2/out/../file.foo to dir2/out/file.bar 
# created all output files 
# done 

    $(shell mkdir dir1 >& /dev/null; touch dir1/file.foo; \ 
      mkdir dir2 >& /dev/null; touch dir2/file.foo) 

    OUTDIRS = dir1/out dir2/out 
    OUTPUTS = dir1/out/file.bar dir2/out/file.bar 

    .DEFAULT_GOAL := all 

    .PHONY: makedirs $(OUTDIRS) 

    .SUFFIXES: .foo .bar 

    %.bar : ../%.foo 
     @echo "copying $< to [email protected]" 
     @cp $< [email protected] 

    all : makedirs outputs 
     @echo "done" 

    outputs : $(OUTPUTS) 
     @echo "created all output files" 

    makedirs : $(OUTDIRS) 
     @mkdir -p $(OUTDIRS) 
     @echo "made directories" 

    clean : 
     @rm -rf dir1 dir2 

Répondre

2

faire $(OUTPUTS) ont une dépendance order-only sur les répertoires eux-mêmes:

$(OUTDIRS) : 
     mkdir -p [email protected] 

$(OUTPUTS) : | $(OUTDIRS) 

Cela guarentee que les répertoires sont créés avant $(OUTPUTS), mais ne causera pas les sorties à reconstruire si les répertoires sont plus récents que les cibles (ce qui est important, car l'horodatage d'un répertoire est défini chaque fois qu'un fichier y est ajouté ...). Remarque: vous pouvez également ajouter un mkdir -p dans votre recette de sortie qui créera le répertoire s'il n'y est pas déjà à chaque fois que vous exécutez une règle de sortie, mais je préfère la méthode ci-dessus.

Note2: dans votre makefile existante, vous pouvez aussi simplement ajouter une ligne: $(OUTPUTS): makedirs, ce qui forcerait la règle makedirs à exécuter avant que les sorties sont construites, mais encore une fois, je préfère la solution ci-dessus :-)

---- EDIT: -----

Quelque chose est bizarre alors - quelle version de make utilisez-vous? Je viens de rencontrer les éléments suivants: notez les sleep 1 « s lors de répertoires, ce qui signifie que s'il y avait un problème de concurrence, il aurait certainement de toucher:

$(shell mkdir dir1 >& /dev/null; touch dir1/file.foo; \ 
     mkdir dir2 >& /dev/null; touch dir2/file.foo) 


OUTDIRS = dir1/out dir2/out 
OUTPUTS = dir1/out/file.bar dir2/out/file.bar 

.DEFAULT_GOAL := all 

$(OUTPUTS) : | $(OUTDIRS) 

$(OUTDIRS) : 
     @echo "making [email protected]" 
     sleep 1 
     mkdir -p [email protected] 
     @echo "done making [email protected]" 


%.bar : ../%.foo 
     @echo "copying $< to [email protected]" 
     @cp $< [email protected] 

all : outputs 
     @echo "done [email protected]" 

outputs : $(OUTPUTS) 
     @echo "created all output files" 

clean : 
     @rm -rf dir1 dir2 

Et la sortie était:

~/sandbox/tmp20> make -j -f Makefile2 
making dir1/out 
making dir2/out 
sleep 1 
sleep 1 
mkdir -p dir1/out 
mkdir -p dir2/out 
done making dir1/out 
done making dir2/out 
copying dir1/out/../file.foo to dir1/out/file.bar 
copying dir2/out/../file.foo to dir2/out/file.bar 
created all output files 
done all 

Notez qu'il crée simultanément dir1/out et dir2/out et n'exécute pas les règles de modèle jusqu'à ce que les deux soient terminées. J'ai également vérifié que la solution que j'ai mentionnée dans la note 2 fonctionne également (au moins sur ma machine ...).

Lorsque vous effectuez des règles de motif, vous pouvez spécifier des dépendances en dehors du motif, de sorte que vous pouvez faire:

foo.o: foo.h 

%.o: %.c 
    recipe here... 

qui rétabliront foo.o si foo.h est plus récente, ou essayer de construire foo.h si elle n'existe pas avant foo.o est construit.

+0

Merci, mais le problème avec une dépendance de commande seule est qu'elle ne garantit pas que la cible sera reconstruite - seulement que les répertoires seront créés. Je ne peux pas obtenir un OOD utilisable dans mon Makefile original, mais je n'ai pas essayé sur cette version réduite - avez-vous essayé une modification spécifique au fichier ci-dessus? – EML

+0

Sur la note: Je ne peux pas faire cela, à cause de la règle de modèle. La correspondance de tige dans le motif échoue si le répertoire n'existe pas déjà (voir le '..'). Il ne semble y avoir aucun moyen de contourner cela (que je peux trouver, de toute façon). – EML

+0

Sur Note2: Je ne pense pas que cela fonctionnera, parce que '$ (OUTPUTS)' doit être construit par la règle de modèle, pas votre nouvelle règle. J'ai essayé diverses combinaisons de ceci, et obtenant makedirs dans la règle de modèle dans le Makefile original, mais aucun d'entre eux a fonctionné. – EML