2011-05-18 18 views
8

Sé que ha habido varias preguntas con títulos similares, pero ninguna parece dar una respuesta a lo que necesito (corríjame si me equivoco).Compilar varios archivos fuente ** cambiados ** a la vez en GNU make

consideran este makefile:

SOURCES=file1.cpp file2.cpp file3.cpp 
OBJECTS=$(SOURCES:.cpp=.o) 
EXECUTABLE=myprog 

all: $(SOURCES) $(EXECUTABLE) 

$(EXECUTABLE): $(OBJECTS) 
    $(CXX) -o [email protected] $(OBJECTS) 

file1.o: file1.cpp file1.h 
file2.o: file2.cpp file2.h file1.h 
file3.o: file3.cpp 

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

Si cambio file1.h, se ejecuta el siguiente:

g++ -c -o file1.o file1.cpp 
g++ -c -o file2.o file2.cpp 
g++ -o myprog file1.o file2.o file3.o 

Lo que me gustaría tener es:

g++ -c file1.cpp file2.cpp 
g++ -o myprog file1.o file2.o file3.o 

(Sé que no puedo especificar el directorio de salida de objetos con GCC, pero puedo vivir con esto, debería ser posible trabajar con algunos cd comandos.)

En nmake, esto se hace con una regla de inferencia de dos puntos (llamado "batch-mode rule"). Básicamente, agrupa las reglas de inferencia (por ejemplo, ".obj.cpp:") para objetivos múltiples e invoca el compilador para todas las dependencias en lugar de una vez por archivo. La variable $< obtiene la lista de dependencias en lugar de solo la primera.

Ahora mismo usamos la construcción en paralelo (make -j) pero tiene sus propios problemas, y el compilador de VC++ funciona mucho mejor en el modo de invocación única, así que preferiría usar eso.

+2

¿por qué su objetivo 'all' depende de su' $ (SOURCES) '? No es necesario ya que '' $ (OBJECTS) 'ya depende de ellos, uno por uno. –

+1

Es solo un ejemplo que encontré. En nuestros archivos makefiles (son bastante complejos) solo dependemos de los ejecutables finales. De cualquier manera, no es de lo que se trata la pregunta. –

+2

El contenedor gcc va a invocar cc1, gas, etc. varias veces. La única invocación de programa que guardará es el envoltorio de gcc mismo. –

Respuesta

1

no veo por qué desea este efecto, pero aquí es cómo conseguirlo (en gnumake):

SOURCES=file1.cpp file2.cpp file3.cpp 
OBJECTS=$(SOURCES:.cpp=.o) 
EXECUTABLE=myprog 

all: $(EXECUTABLE) 

$(EXECUTABLE): $(SOURCES) 
    $(CXX) $(CXXFLAGS) -c $? 
    $(CXX) -o [email protected] $(OBJECTS) 

EDIT:
Me sorprende que esta solución funciona - no hay algo está mal con mi idea de lo que hace Make, pero no creo que funcione en su caso, con dependencias de encabezado, sin el siguiente kludge. (Hay uno o dos otros enfoques que podrían funcionar, si esto no tiene éxito.)

SOURCES=file1.cpp file2.cpp file3.cpp 
OBJECTS=$(SOURCES:.cpp=.o) 
EXECUTABLE=myprog 

all: $(EXECUTABLE) 

$(EXECUTABLE): $(OBJECTS) 
    $(CXX) -o [email protected] $(OBJECTS) 

file1.cpp: file1.h 
file2.cpp: file2.h file1.h 

$(SOURCES): 
    @touch [email protected] 

$(OBJECTS): $(SOURCES) 
    $(CXX) $(CXXFLAGS) -c $? 
    @touch $(OBJECTS) 
+0

Gracias, esta es una posibilidad. Sin embargo, con esto tendría que hacer tanto la compilación como la vinculación en la misma regla. ¿De alguna manera puedo mantener el enlace y la compilación separados? –

+0

Un problema con esta solución es que no rastrea las dependencias de los archivos individuales (que hemos declarado). Por ejemplo, cambiar un encabezado no desencadena la recompilación. Encontré una solución que casi funciona [aquí] (http://lists.gnu.org/archive/html/help-make/2001-03/msg00064.html) pero necesitará cambiar todas nuestras dependencias de .obj a. cpp. Hmm ... –

1

Puede hacer gnumake hace lo que quiere mediante la recopilación de los archivos que ser reconstruido en la regla de construcción y luego en realidad construyéndolos cuando vincula:

SOURCES=file1.cpp file2.cpp file3.cpp 
OBJECTS=$(SOURCES:.cpp=.o) 
EXECUTABLE=myprog 

all: $(EXECUTABLE) 

.PHONY: build_list 

build_list: 
     -rm -f build_list 

$(OBJECTS): %.o: %.cpp | build_list 
     echo $< >> build_list 

$(EXECUTABLE): build_list $(OBJECTS) 
     if [ -r build_list ]; then $(CXX) $(CXXFLAGS) -c `cat build_list`; fi 
     $(CXX) -o [email protected] $(OBJECTS) 

file1.o: file1.h 
file2.o: file2.h file1.h 
+0

Esto parece interesante, ya veremos si funciona. Aunque me pregunto si puedes usar una variable make en lugar de un archivo de lista. –

Cuestiones relacionadas