2010-09-15 8 views
12

To jest mój obecny plik Makefile.Dlaczego ten plik Makefile wykonuje cel na "make clean"

CXX  = g++ 
CXXFLAGS = -Wall -O3 
LDFLAGS = 

TARGET = testcpp 
SRCS = main.cpp object.cpp foo.cpp 
OBJS = $(SRCS:.cpp=.o) 
DEPS = $(SRCS:.cpp=.d) 


.PHONY: clean all 

all: $(TARGET) 

$(TARGET): $(OBJS) 
    $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET) 

.cpp.o: 
    $(CXX) $(CXXFLAGS) -c $< -o [email protected] 

%.d: %.cpp 
    $(CXX) -M $(CXXFLAGS) $< > [email protected] 

clean: 
    rm -f $(OBJS) $(DEPS) $(TARGET) 

-include $(DEPS) 

Działa doskonale z jednym wyjątkiem. Jeśli katalog jest już czysty (nie * .d, * .o) i uruchomić „make clean”, to ponownie tworzy zależności, a następnie usuwa je natychmiast:

[[email protected] proj]$ make 
g++ -M -Wall -O3 foo.cpp > foo.d 
g++ -M -Wall -O3 object.cpp > object.d 
g++ -M -Wall -O3 main.cpp > main.d 
g++ -Wall -O3 -c main.cpp -o main.o 
g++ -Wall -O3 -c object.cpp -o object.o 
g++ -Wall -O3 -c foo.cpp -o foo.o 
g++ -Wall -O3 main.o object.o foo.o -o testcpp 
[[email protected] proj]$ make clean 
rm -f main.o object.o foo.o main.d object.d foo.d testcpp 
[[email protected] proj]$ make clean 
g++ -M -Wall -O3 foo.cpp > foo.d 
g++ -M -Wall -O3 object.cpp > object.d 
g++ -M -Wall -O3 main.cpp > main.d 
rm -f main.o object.o foo.o main.d object.d foo.d testcpp 
[[email protected] proj]$ 

Nie rozumiem dlaczego drugie "wyczyść" spowoduje ponowne wygenerowanie plików zależności. Jak mogę tego uniknąć? To nie jest wielka sprawa dla tego zmyślonego przykładu, ale dla dużego projektu może to być dość czasochłonne.

Dzięki.

+4

Czasami warto czytać http://mad-scientist.net/make/autodep.html, który opisuje rozwiązanie do śledzenia obejmują zależności, które pozwala uniknąć tego problemu, jak również zaskakująco wiele innych powikłań. – slowdog

Odpowiedz

21

Ponieważ pliki .d są bezwarunkowo -include. Jeśli chodzi o make wie, mogą dodawać zależności lub polecenia do celu clean. Wszystkie pliki d są najpierw budowane z tego powodu, w przeciwnym razie można uzyskać niepoprawną lub nieudaną kompilację. Aby to wyłączyć, chcesz warunkowo zawierać pliki z zależnościami:

ifneq ($(MAKECMDGOALS),clean) 
-include $(DEPS) 
endif 

Alternatywnym rozwiązaniem jest generowanie plików z zależnościami przy użyciu touch i mieć je zastąpić rzeczywistymi danymi jako efekt uboczny kompilacji. W ten sposób automake monitoruje zależność, ponieważ sprawia, że ​​jednorazowe kompilacje są szybsze. Sprawdź opcje -MD i -MMD na gcc, jeśli chcesz iść tą trasą. Użyj reguły wzoru, takiej jak:

%.d: 
    @touch [email protected] 

Aby wstępnie utworzyć pliki zależności.

+0

Ooh, dobra sztuczka. Nie wiedziałem o '$ (MAKECMDGOALS)'. – zwol

+0

Po prostu notka: możliwe jest zbudowanie kilku celów naraz - na przykład: 'make all clean' ustawi' $ (MAKECMDGOALS) 'na' all clean', co nadal będzie wywoływać treść podanej instrukcji. Nie byłoby tak źle, jednak cel 'all' wymaga dołączenia' $ (DEPS) '. Gdybyś miał inny cel, który mógłby być wywoływany z czystym, musiałbyś być bardziej sprytny w swoim stwierdzeniu "ifneq" – John

4

Chce ponownie wygenerować pliki zależności, ponieważ zawsze stara się ponownie wygenerować wszystkie pliki Makefile, w tym -include'd pliki makefiles, zanim zrobi cokolwiek innego. (Cóż, właściwie dla mnie to nie robi - mam GNU Make 3.81 - więc może to błąd w twojej wersji, który został naprawiony, albo optymalizacja, którą moja ma, a twoja nie.) W każdym razie.)

Najprostszym sposobem jest napisanie reguł, aby generowały pliki .d jako efekt uboczny zwykłej kompilacji, zamiast dawać wyraźne reguły ich generowania. W ten sposób, gdy ich tam nie ma, Make nie wie, jak je wygenerować, więc nie próbuje (w czystym drzewie wystarczą reguły .cpp.o, nie potrzebujesz potrzebujesz pliku nagłówkowego zależności). Spójrz na plik Makefile generowany przez Automake - prosty - aby zobaczyć, jak to się robi.

2

Wiodącym - w -include oznacza, że ​​makenie będzie narzekać jeśli zależności brakuje i nie mogą być przerobione, ale to nie znaczy, że nie postara się uczynić je pierwszy (i, w tym przypadku, odnieść sukces) - w końcu wszystko, co jest interesujące lub ważne, może być w dołączonych plikach, skąd próbujemy spróbować. Nie sądzę, żeby można to było powstrzymać.

Dla dokumentów na temat include i -include, patrz here.

4

Jeśli chcesz pominąć uwzględnienie wielu celów, możesz użyć funkcji filter.

MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc 

# Include only if the goal needs it 
ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),) 
    -include $(DEPS) 
endif 
Powiązane problemy