2016-07-29 29 views
0

Ich möchte, dass eine Regel sich wie eine Funktion verhält, die zB alle meine temporären Ziele gzip. Ich schrieb diese Regeln in einem Makefile:Gnu-make-Regel als Funktion anwenden

%.file0:    
     touch [email protected]  

%.file1: %  
     touch [email protected]  

%.file2: %   
     touch [email protected]  

%.gz: %  
     echo "zipping to [email protected]" 
     touch [email protected] 

I

$ make -n dotted.file.file0.file1.file2.gz -f makefile 
touch dotted.file.file0 
touch dotted.file.file0.file1 
touch dotted.file.file0.file1.file2 
echo "zipping to dotted.file.file0.file1.file2.gz" 
rm dotted.file.file0 dotted.file.file0.file1.file2 dotted.file.file0.file1 

Mein letztes Ziel erfolgreich gzipped werden aufrufen können. Ich kann dann gzip dotted.file.file0.file1 vor:

$ make -n dotted.file.file0.file1.gz.file2 -f makefile 
touch dotted.file.file0             
touch dotted.file.file0.file1            
echo "zipping to dotted.file.file0.file1.gz"        
touch dotted.file.file0.file1.gz.file2          
rm dotted.file.file0 dotted.file.file0.file1.gz dotted.file.file0.file1 

Diese Datei wird auch vor die Regel% .file2 gzip werden wird. Aber ich kann nicht mehrere Ziele gzip:

$ make -n dotted.file.file0.file1.gz.file2.gz -f makefile 
make: *** No rule to make target `dotted.file.file0.file1.gz.file2.gz'. Stop. 

Wie kann ich das tun, das heißt auf mehrere Ziele, um die% gz Regel anwenden?


EDIT 1

Von einem anderen Standpunkt aus betrachtet, habe ich versucht, meine Regeln auf diese Weise umschreiben:

%.file0:      
     touch [email protected]    

%.file1: %.gz    
     touch [email protected]    

%.file2: %.gz    
     touch [email protected]    

%.gz: %      
     echo "zipping to [email protected]" 
     touch [email protected] 

Dann rufe ich machen:

$ make -n dotted.file.file0.file1.file2 -f makefile 
make: *** No rule to make target `dotted.file.file0.file1.file2'. Stop. 

Ich erwarte/Wunsch gnu-make, um die Regeln dieser Reihenfolge auszuführen:

- ask for the file dotted.file.file0.file1.file2 
- go to rule %.file2 
- ask for the dependency dotted.file.file0.file1.gz 
- go to rule %.gz 
- as for the dependency dotted.file.file0.file1 
- go to rule %.file1 
- as for the dependency dotted.file.file0.gz 
- go to rule %.gz 
- as for the dependency dotted.file.file0 
- go to rule %.file0 
- create file dotted.file.file0 

Wenn ich jedoch nur eine Regel anlege, %.gz anzuwenden, wird es dieses Mal funktionieren.

Die Make-Datei:

%.file0:      
     touch [email protected]    

%.file1: %.gz # !!! Notice I left this single dependency to the rule %.gz   
     touch [email protected]    

%.file2: % ## !!! Notice I removed the .gz here    
     touch [email protected]    

%.gz: %      
     echo "zipping to [email protected]" 
     touch [email protected] 

Der Befehl:

$make -n dotted.file.file0.file1.file2 -f makefile 
touch dotted.file.file0      
touch dotted.file.file0.file1      
echo "zipping to dotted.file.file0.file1.gz"   
touch dotted.file.file0.file1.gz      
touch dotted.file.file0.file1.file2      
rm dotted.file.file0.file1.gz dotted.file.file0 dotted.file.file0.file1 
+0

Gibt es einen Grund, warum Sie diese zusammengesetzten Dateinamen (z. B. 'bar.file0.file1.file2' anstelle von' bar.file2') möchten? – Beta

+0

Der einzige Grund ist, zu verfolgen, welche Schritte (Regeln) auf die Dateien angewendet wurden, das ist informativ. Ist das der Grund, dass make die gleiche Regel nicht zweimal anwendet? – kaligne

+0

Sie betteln die Frage an. Erstellen von 'bar.file0.file1.file2' kann wahrscheinlich mit etwas Mühe und Klugheit erledigt werden; Das Erstellen von 'bar.file2' ist viel einfacher und der Name liefert genau die gleiche Information. – Beta

Antwort

0

das Problem bei dem ersten Version ist, dass Sie statische Muster Regeln brauchen würden, nicht implizite Regeln. Das Folgende erledigt der Job mit GNU, indem er Shell-Aufrufe an awk verwendet, um explizite Listen der Ziele *.file1, *.file2 und *.gz aus den angegebenen make-Zielen zu erstellen. Es verwendet auch foreach-eval-call Kombinationen, um so viele Regeln (ohne Rezepte) wie nötig zu instanziieren, um alle Abhängigkeiten explizit auszudrücken. Ich muss zugeben, dass diese Art von Make eher ungewöhnlich ist, aber Ihr Problem ist ungewöhnlich, auch ...

SUFFIXES := file1 file2 gz 

# For goal $(1) and suffix $(2), build the list of all possible stems <S> such 
# that $(1) matches the ^<S>\.$(2)(\..*)? regular expression. Concatenate this 
# list to the $(2) make variable. 
define SPLIT_rule 
$(2) += $$(shell echo $(1) | awk -F.$(2) '{for(i=1;i<=NF;i++){for(j=1;j<=i;j++)printf("%s",$$$$j);printf(".$(2) ")}}') 
endef 

# For goal $(1), instantiate SPLIT_rule for each suffix. 
define GOAL_rule 
$(foreach suffix,$(SUFFIXES),$(eval $(call SPLIT_rule,$(1),$(suffix)))) 
endef 

$(foreach goal,$(MAKECMDGOALS),$(eval $(call GOAL_rule,$(goal)))) 

# For suffix $(1), instantiate the static pattern rule. 
define SUFFIX_rule 
$$($(1)): %.$(1): % 
endef 

$(foreach suffix,$(SUFFIXES),$(eval $(call SUFFIX_rule,$(suffix)))) 

%.file0: 
    touch [email protected] 

%.file1: % 
    touch [email protected] 

%.file2: % 
    touch [email protected] 

%.gz: % 
    echo "zipping to [email protected]" 
    touch [email protected] 

Und:

$ goal1=dotted.file.file0.file1.file2.gz 
$ make -n $goal1 
touch dotted.file.file0 
touch dotted.file.file0.file1 
touch dotted.file.file0.file1.file2 
echo "zipping to dotted.file.file0.file1.file2.gz" 
touch dotted.file.file0.file1.file2.gz 

$ goal2=dotted.file.file0.file1.gz.file2 
$ make -n $goal2 
touch dotted.file.file0 
touch dotted.file.file0.file1 
echo "zipping to dotted.file.file0.file1.gz" 
touch dotted.file.file0.file1.gz 
touch dotted.file.file0.file1.gz.file2 

$ goal3=dotted.file.file0.file1.gz.file2.gz 
$ make -n $goal3 
touch dotted.file.file0 
touch dotted.file.file0.file1 
echo "zipping to dotted.file.file0.file1.gz" 
touch dotted.file.file0.file1.gz 
touch dotted.file.file0.file1.gz.file2 
echo "zipping to dotted.file.file0.file1.gz.file2.gz" 
touch dotted.file.file0.file1.gz.file2.gz 

$ goal4=dotted.file.file0.file1.file2 
$ make -n $goal4 
touch dotted.file.file0 
touch dotted.file.file0.file1 
touch dotted.file.file0.file1.file2 

$ all="$goal1 $goal2 $goal3 $goal4" 
$ make -n $all 
touch dotted.file.file0 
touch dotted.file.file0.file1 
touch dotted.file.file0.file1.file2 
echo "zipping to dotted.file.file0.file1.file2.gz" 
touch dotted.file.file0.file1.file2.gz 
echo "zipping to dotted.file.file0.file1.gz" 
touch dotted.file.file0.file1.gz 
touch dotted.file.file0.file1.gz.file2 
echo "zipping to dotted.file.file0.file1.gz.file2.gz" 
touch dotted.file.file0.file1.gz.file2.gz 
make: 'dotted.file.file0.file1.file2' is up to date. 

Hinweis: da alle Zwischenprodukte nicht mehr implizit sind, sind sie nicht automatisch gelöscht, als ob sie in Ihrer ersten Version PRECIOUS deklariert wären. Dies ist der Grund, warum in den Ausgängen kein rm ... mehr vorhanden ist.