2010-09-15 10 views
12

Este es mi archivo MAKE actual.¿Por qué este archivo MAKE ejecuta un objetivo en '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) 

Funciona perfectamente con una excepción. Si el directorio ya está limpia (sin * .d, * .o) y ejecute 'make clean', que recrea las dependencias, a continuación, los elimina de inmediato:

[[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]$ 

No entiendo por qué el el segundo 'make clean' generaría de nuevo los archivos de dependencia. ¿Cómo puedo evitar esto? Esto no es un gran problema para este ejemplo artificial, pero para un proyecto grande, puede llevar bastante tiempo.

Gracias.

+4

Es posible que desee leer http://mad-scientist.net/make/autodep.html, que describe una solución para el seguimiento incluyen dependencias que evita este problema, así como los sorprendentemente muchas otras complicaciones. – slowdog

Respuesta

21

Es porque los archivos .d están siendo -include d incondicionalmente. En cuanto a make sabe, podrían agregar dependencias o comandos al objetivo clean. Todos los archivos d include se crean primero por este motivo, de lo contrario, es posible que obtenga una compilación incorrecta o fallida. Para desactivar esta opción, que desea incluir condicionalmente los archivos de dependencia:

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

Una solución alternativa es generar los archivos de dependencia utilizando touch y tenerlos reemplazados por datos reales como un efecto secundario de la compilación. Así es como automake realiza su seguimiento de dependencia, ya que hace que las compilaciones únicas sean más rápidas. Mire en las opciones -MD y -MMD al gcc si desea seguir esta ruta. Use una regla de patrón como:

%.d: 
    @touch [email protected] 

Para crear inicialmente los archivos de dependencia.

+0

Ooh, buen truco. No sabía acerca de '$ (MAKECMDGOALS)'. – zwol

+0

Solo una nota: es posible construir varios objetivos a la vez, por ejemplo: 'make all clean' establecería' $ (MAKECMDGOALS) 'en' all clean', lo que aún invocaría el cuerpo de la instrucción mencionada. Esto no sería tan malo, aunque como el objetivo 'all' requiere que se incluya' $ (DEPS) '. Si tuviera otro objetivo que podría ser invocado con clean, entonces tendría que ser más inteligente en su declaración 'ifneq' – John

4

Quiere regenerar los archivos de dependencia porque siempre intenta volver a generar todos los archivos MAKE, incluyendo -include'd makefiles, antes de hacer cualquier otra cosa. (Bueno, en realidad, para mí no es eso - Tengo GNU Make 3.81 - así que tal vez es un error en su versión que fue corregido, o una optimización que la mía tiene y la suya no. Pero de todos modos.)

La manera más fácil de evitar esto es escribir sus reglas para que generen los archivos .d como un efecto secundario de la compilación regular, en lugar de dar reglas explícitas para generarlos. De esta forma, cuando no están allí, Make no sabe cómo generarlos, por lo que no intenta (en un árbol limpio, las reglas .cpp.o son suficientes, no necesita el archivo de encabezado dependencias). Mire un archivo MAKE generado por Automake, uno simple, para ver cómo se hace.

2

El líder - en -include significa que makeno se quejará si las dependencias se han perdido y no pueden ser rehechos, pero eso no quiere decir que no tratará de hacerlos primera (y, en este caso, tener éxito) - después de todo, cualquier cosa interesante 0 importante podría estar en los archivos incluidos, por lo que tratemos de intentarlo. No creo que haya una manera de detener eso.

Para documentos en include y -include, vea here.

4

Si desea omitir el incluir para destinos múltiples, puede usar la función 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 
Cuestiones relacionadas