122 votes

Règle GNU Makefile générant quelques cibles à partir d'un seul fichier source

Je suis tenter de faire le suivant. Il y a un programme, appelez foo-bin, qui tient en un seul fichier d'entrée et génère deux fichiers de sortie. Un muet Makefile règle serait:

file-a.out file-b.out: input.in
    foo-bin input.in file-a.out file-b.out

Toutefois, cela ne veut pas dire make , en aucune façon que les deux objectifs seront générés simultanément. C'est très bien lors de l'exécution d' make dans la série, mais sera susceptible de causer des problèmes si l'on essaie make -j16 ou quelque chose d'aussi fou.

La question est de savoir si il existe un moyen pour écrire un Makefile règle pour ce cas? Clairement, il serait de générer un DAG, mais de toute façon le GNU make manuel ne précise pas comment cette affaire pourrait être manipulés.

L'exécution du même code deux fois et en ne générant qu'un résultat est hors de question, car le calcul prend du temps (pense: les heures). La sortie d'un seul fichier doit également être assez difficile, car il est fréquemment utilisé comme entrée pour GNUPLOT qui ne sait pas comment gérer qu'une fraction d'un fichier de données.

137voto

slowdog Points 2837

L'astuce consiste à utiliser un modèle de règle avec des objectifs multiples. Dans ce cas, supposons que les deux objectifs sont créés par une seule invocation de la commande.

tous: fichier-un.fichier-b.hors
%-un.out %-b.: entrée.dans
 foo-bin entrée.dans $*-un.$*-b.hors

Cette différence d'interprétation entre le modèle de règles et les règles normales n'est pas exactement du sens, mais il est utile pour les cas comme cela, et il est documenté dans le manuel.

Cette astuce peut être utilisée pour n'importe quel nombre de fichiers de sortie, aussi longtemps que leurs noms ont en commun certaines sous-chaîne pour l' % de match.

63voto

deemer Points 612

N'ont pas de toute façon intuitive pour le faire, mais il y a deux décent solutions de contournement.

Tout d'abord, si les cibles concernées ont une racine commune, vous pouvez utiliser un préfixe de la règle (avec GNU make). C'est, si vous voulez fixer la règle suivante:

object.out1 object.out2: object.input
    foo-bin object.input object.out1 object.out2

Vous pouvez l'écrire de cette façon:

%.out1 %.out2: %.input
    foo-bin $*.input $*.out1 $*.out2

(À l'aide du modèle de la règle de la variable $*, qui signifie " correspondant à la partie du modèle)

Si vous voulez être portable à la non-GNU Make implémentations ou si vos fichiers ne peuvent pas être nommés pour correspondre à un modèle de règle, il est une autre façon:

file-a.out file-b.out: input.in.intermediate

.INTERMEDIATE: input.in.intermediate
input.in.intermediate: input.in
    foo-bin input.in file-a.out file-b.out

Cela dit de faire une entrée.dans.intermédiaires ne sont pas exister avant de faire est d'exécuter, de sorte que son absence (ou son timestamp) ne cause pas de foo-bin pour être exécuté par erreur. Et si l'un des fichiers-un.ou fichier-b.ou les deux sont out-of-date (par rapport à l'entrée.dans l'), foo-bin sera exécuté qu'une fois. Vous pouvez utiliser .SECONDAIRE au lieu de .INTERMÉDIAIRE, qui ordonnera de ne PAS supprimer un hypothétique de saisie nom de fichier.dans.intermédiaire. Cette méthode est également sûr pour les parallèles de faire des builds.

11voto

Peter Tillemans Points 20129

Je le résoudrais comme suit:

 file-a.out: input.in
    foo-bin input.in file-a.out file-b.out   

file-b.out: file-a.out
    #do nothing
    noop
 

Dans ce cas, make parallèle 'sérialisera' en créant a et b mais comme créer b ne fait rien, cela ne prend pas de temps.

2voto

richard Points 1651

C'est de cette façon que je le fais. D'abord j'ai toujours séparé de pré-requesits de recettes. Alors dans ce cas une nouvelle cible pour faire la recette.

all: file-a.out file-b.out #first rule

file-a.out file-b.out: input.in

file-a.out file-b.out: dummy-a-and-b.out

.SECONDARY:dummy-a-and-b.out
dummy-a-and-b.out:
    echo creating: file-a.out file-b.out
    touch file-a.out file-b.out

La première fois:
1. Nous essayons de créer un fichier-un.hors, mais factice-a-et-b.out doit être fait en premier afin de faire fonctionner le mannequin-a-et-b.de recettes.
2. Nous essayons de créer un fichier-b.hors, le mannequin-a-et-b.jusqu'à ce jour.

La deuxième fois:
1. Nous essayons de créer un fichier-un.: faire regarde les conditions préalables, les normales conditions préalables sont à jour, secondaire conditions requises sont manquantes sont donc ignorées.
2. Nous essayons de créer un fichier-b.: faire regarde les conditions préalables, les normales conditions préalables sont à jour, secondaire conditions requises sont manquantes sont donc ignorées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X