2016-03-27 4 views
0

Ich habe eine Verzeichnisstruktur, die wie folgt aussieht:Wie bekomme ich die zweite Erweiterung mit zwei Regeln mit demselben Ziel, das% enthält?

$ tree 
. 
|-- dir 
| `-- subdir 
|  `-- data 
`-- makefile 

wo data eine Datei ist. Mein makefile sieht wie folgt aus:

all: dir/analysis 

.SECONDEXPANSION: 
%/analysis: %/subdir 
%/analysis: $(addsuffix /data, $$^) 
     @echo TARGET: [email protected] DEPS: $^ 
     touch [email protected] 

Als ich make laufen, würde ich das Ergebnis erwarten wie folgt aussehen:

TARGET: dir/analysis DEPS: dir/subdir/data dir/subdir 
touch dir/analysis 

Stattdessen ist es nur Berichte

make: *** No rule to make target `dir/analysis', needed by `all'. Stop. 

Wenn ich ändern die erste Regel zu dir/analysis: dir/subdir dann funktioniert es wie ich erwartet habe. Also vermute ich, dass make die erste Regel ignoriert und direkt zur zweiten überspringt, wenn die erste Regel %/analysis: %/subdir ist. Es funktioniert auch wie erwartet, wenn beide Regeln dir/analysis als Ziel haben und nicht nur die erste Regel. MadScientists Antwort auf eine andere Frage here schien auf mein Problem zutreffen. Ich habe versucht, Regeln wie

dummy_target: dir/subdir 
     mkdir -p dir/subdir 

und

dir/subdir: 
     mkdir -p dir/subdir 

bis Ende makefile Zugabe zu versuchen, die Abhängigkeit von der ersten Regel ein explizites Ziel zu machen, aber das hat nichts ändern. Ich bin ziemlich neu zu make, so vermisse ich wahrscheinlich etwas ziemlich dummes, aber ich kann nicht für das Leben von mir herausfinden. Wie erhalte ich die ersten und zweiten Regeln in der Reihenfolge, in der sie geschrieben wurden? Ich benutze Version 3.81, falls das wichtig ist.

--EDIT--

Wenn ich diesen Befehl ausführt, tatsächlich einen Befehl nach der ersten Regel hinzuzufügen, wie @echo RULE 1 dann und nicht die zweite.

Antwort

3

Ich denke, dass Sie die Make-Datei zu verstehen:

# Original 
all: dir/analysis 

.SECONDEXPANSION: 
%/analysis: %/subdir 
%/analysis: $(addsuffix /data, $$^) 
     @echo TARGET: [email protected] DEPS: $^ 
     touch [email protected] 

wie folgt aus:

  • standardmäßig wir machen dir/analysis
  • Wir fordern sekundäre Expansion
  • Wir sagen, dass was/analysis hängt von was auch immer/subdir. So die dir/subdir eine Voraussetzung für dir/analysis
  • Wir machen auch sagen, dass was/analysis auf die Sache ab, die wir von suffixing bekommen /data dem Stand der Voraussetzungen von was/analysis. (Sekundär Erweiterung von $$^ gibt uns die vorherigen Voraussetzungen des Ziels).Und seit den vorherigen Voraussetzungen von dir/analysis sind dir/subdir, dass jetzt macht dir/subdir dir/subdir/data die neuen Voraussetzungen von dir/analysis.

Daraus ergibt sich die Ausgabe des Rezepts sollte sein:

TARGET: dir/analysis DEPS: dir/subdir/data dir/subdir 
touch dir/analysis 

Dieses Verständnis schlecht ist falsch. Sie verwirren und verschmelzen die Operation von Musterregeln mit der Operation oder gewöhnlichen Regeln.

Wenn ein Make-Datei sagt, zum Beispiel:

# A 
xx: xa 

xx: xb 

xx: xc 
    touch [email protected] 

oder sogar:

# B 
xx: xa 

xx: xb 

%x: %c 
    touch [email protected] 

dann die Voraussetzungen aller leeren Regeln für die Ziel xx kombiniert werden mit denen die (eine) Nicht leere Regel, wenn xx als Ziel betrachtet wird. So # A entspricht:

xx: xa xb xc 
    touch [email protected] 

und # B entspricht:

xx: xa xb 

%x: %c 
    touch [email protected] 

und in beiden Fällen die Voraussetzungen des xxxa xb xc sind.

jedoch:

%x: %a 

%x: %b 
    touch [email protected] 

ist nicht entspricht:

%x: %a %b 
    touch [email protected] 

Wenn Sie jemals eine leere Muster Regel schreiben, seine Wirkung ist einfach jede vorheriges Muster Regel zu löschen mit dem gleichen Ziel und den vorausgesetzten Mustern. Und wenn Sie jemals eine nicht leere Musterregel schreiben, ersetzen Sie einfach jede vorherige Musterregel mit den gleichen Ziel und Voraussetzung Muster. Siehe 10.5.6 Canceling Implicit Rules

So:

.SECONDEXPANSION: 
%/analysis: %/subdir 
%/analysis: $(addsuffix /data, $$^) 
    @echo TARGET: [email protected] DEPS: $^ 
    touch [email protected] 

entspricht:

.SECONDEXPANSION: 
%/analysis: $(addsuffix /data, $$^) 
    @echo TARGET: [email protected] DEPS: $^ 
    touch [email protected] 

Dann, wenn dieses Muster Regel in Bezug auf dir/analysis betrachtet wird, gibt es keine vor Voraussetzungen: $^ wird erweitern auf die leere Zeichenfolge und in der sekundären Erweiterung, so wird $$^.So endlich ist das Rezept entspricht:

# Residual 
%/analysis: /data 
    @echo TARGET: [email protected] DEPS: $^ 
    touch [email protected] 

Sie sich von dieser befriedigen kann durch beide der # Original und # Residual Makefiles im Debug-Modus (-d) und Vergleichen der Ausgänge aktiv.

Dies erklärt, warum die Ausgaben in beiden Fällen schließen:

make: *** No rule to make target 'dir/analysis', needed by 'all'. Stop. 

Ein Muster Regel nur ein Ziel wenn dabei einen Weg für das Ziel getroffen werden bietet machen instanziiert wird. Warum sonst noch wählen? Da die Voraussetzung /data nicht existiert, ist die Musterregel nicht durchführbar und wird verworfen. So wie wenn man versuchte, make foo.o mit der Make-Datei:

%.o: %c 
    touch [email protected] 

wenn kein foo.c im Verzeichnis ist.

Wenn Sie wirklich die Ausgabe, die Sie erwartet haben, um sehen möchten, dann können Sie es aus erhalten:

.PHONY: all clean 

all: dir/analysis 

%/analysis: %/subdir %/subdir/data 
    @echo TARGET: [email protected] DEPS: $^ 
    touch [email protected] 

clean: 
    rm -f dir/analysis 

Aber es ist schwer zu glauben, dass das, was Sie wirklich sehen wollen. Dieses Makefile macht die Analyse abhängig von den Daten und auch auf das Verzeichnis, in dem die Daten befindet. Was kann der Sinn sein?

%/analysis: %/subdir/data 

drückt vermutlich die gewünschte Beziehung zwischen den Daten und der Analyse: -

  • Wenn die Daten nicht existieren dann die Analyse nicht mehr aktuell ist und nicht gemacht werden kann (bis Sie einige Daten erhalten).
  • Wenn die Daten vorhanden und älter als die Analyse ist, muss die Analyse nicht durchgeführt werden.
  • Wenn die Daten vorhanden sind und neuer als die Analyse ist, kann und wird die Analyse durchgeführt.

Durch all dir/subdir eine unabhängige Voraussetzung machen, dass Sie erreichen, ist eine Anforderung einzuführen, um die Analyse neu zu machen, wenn es als älter wird das Verzeichnis in , die die Daten befinden - unabhängig von den Daten. Wenn also z.B. Ich starte touch dir/subdir, , die make benötigen, um die Analyse erneut auszuführen, obwohl sich die Daten nicht geändert haben.

Ich kann nur Sinn Ihrer Motivation machen damit auch in Realität angenommen Sie make-wollen machen die Daten, und das Verzeichnis, in dem sie sich befindet, wenn sie existieren nicht passieren, wenn eine Analyse erforderlich ist.Wenn das die Situation dann ist wollen Sie eine Make-Datei auf den Linien von:

.PHONY: all clean 

all: dir/analysis 

.SECONDARY: 

%/subdir: 
    mkdir -p [email protected] 

%/subdir/data: | %/subdir 
    touch [email protected] 

%/analysis: %/subdir/data 
    @echo TARGET: [email protected] DEPS: $^ 
    touch [email protected] 

clean: 
    rm -f dir/analysis dir/subdir/data 

Hier wird die Musterregel:

%/subdir/data: | %/subdir 

macht %/subdir ein order-only prerequisite von %/subdir/data. Es bedeutet, dass /dir/subdir ist nicht berücksichtigt bei der Bestimmung, ob /dir/subdir/data Bedürfnisse gemacht werden, aber wenn es bestimmt wird, dass /dir/subdir/data gemacht werden soll, dann wird /dir/subdir zuerst gemacht werden. Dieser Weg, /dir/subdir wird erstellt, wenn es nicht existiert, wenn Sie es brauchen, um die Daten dort zu setzen, aber keinen Einfluss haben auf, ob Sie die Daten oder die Analyse machen müssen. Das spezielle Ziel .SECONDARY ist ein technicality. Es weist make an, nachfolgende Ziele nicht automatisch zu löschen, dass es zu intermediate Artefakten führt, die aus verketteten Musterregeln hervorgehen. Ohne es, in diesem Beispiel make würde folgern, dass dir/subdir/data und dir/subdir/ sind nur Abfallprodukte der Herstellung dir/analysis und löschen sie automatisch am Ende.

Wenn Sie das Make-Datei laufen zunächst ohne dir/subdir/data und ohne dir/subdir/ Sie erhalten:

$ make 
mkdir -p dir/subdir 
touch dir/subdir/data 
TARGET: dir/analysis DEPS: dir/subdir/data 
touch dir/analysis 

Und anschließend:

$ make clean 
rm -f dir/analysis dir/subdir/data 
$ make 
touch dir/subdir/data 
TARGET: dir/analysis DEPS: dir/subdir/data 
touch dir/analysis 

Und dann:

$ make 
make: Nothing to be done for 'all'. 
$ touch dir/subdir 
$ make 
make: Nothing to be done for 'all'. 
+0

Danke die für die Aufnahme Zeit eine so hilfreiche und ausführliche Antwort zu schreiben. Ich würde dir mehr danken, wenn ich könnte. Das hilft mir zu sehen, dass ich für das, was ich erreichen möchte, eine andere Strategie brauche. Ich war dabei, mehr über meine weiteren Ziele und das, was ich mit Second Expansion in meinem realen System zu tun versuchte, zu diskutieren, aber ich denke, das wäre besser für eine separate Frage geeignet. –

Verwandte Themen