dependencies - titulos - Makefile, dependencias de encabezado
que es un tag h2 (9)
Digamos que tengo un archivo MAKE con la regla
%.o: %.c
gcc -Wall -Iinclude ...
Quiero * .o ser reconstruido cada vez que un archivo de cabecera cambia. En lugar de elaborar una lista de dependencias, cada vez que cualquier archivo de encabezado en /include
cambia, todos los objetos en el directorio deben reconstruirse.
No puedo pensar en una buena forma de cambiar la regla para acomodar esto, estoy abierto a sugerencias. Puntos de bonificación si la lista de encabezados no tiene que estar codificada
¿Qué tal algo así como:
includes = $(wildcard include/*.h)
%.o: %.c ${includes}
gcc -Wall -Iinclude ...
También podría usar los comodines directamente, pero tiendo a encontrar que los necesito en más de un lugar.
Tenga en cuenta que esto solo funciona bien en proyectos pequeños, ya que supone que cada archivo objeto depende de cada archivo de encabezado.
Aquí hay un trazador de líneas:
CPPFLAGS = -MMD
-include $(OBJS:.c=.d)
Esto funciona con la receta de OBJS
predeterminada, siempre que tenga una lista de todos sus archivos de objeto en OBJS
.
Como publiqué here gcc puede crear dependencias y compilar al mismo tiempo:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<
El parámetro ''-MF'' especifica un archivo para almacenar las dependencias.
El guión al inicio de ''-include'' le dice a Make que continúe cuando el archivo .d no exista (p. Ej., En la primera compilación).
Tenga en cuenta que parece haber un error en gcc con respecto a la opción -o. Si configura el nombre del archivo del objeto para que diga obj / _file__c.o, el archivo .d generado seguirá conteniendo el archivo .o, no obj / _file__c.o.
Esto hará bien el trabajo e incluso manejará los subdirectores especificados:
$(CC) $(CFLAGS) -MD -o $@ $<
probado con gcc 4.8.3
La mayoría de las respuestas son sorprendentemente complicadas o erróneas. Sin embargo, ejemplos simples y robustos han sido publicados en otra parte [ codereview ]. Es cierto que las opciones proporcionadas por el preprocesador gnu son un poco confusas. Sin embargo, la eliminación de todos los directorios del objetivo de compilación con -MM
está documentada y no es un error [ gpp ]:
Por defecto, CPP toma el nombre del archivo de entrada principal, elimina cualquier componente de directorio y cualquier sufijo de archivo, como ''.c'', y agrega el sufijo de objeto habitual de la plataforma.
La opción (algo más reciente) -MMD
es probablemente lo que quieres. Para completar, un ejemplo de un archivo MAKE que admite varios directorios src y compilar directorios con algunos comentarios. Para una versión simple sin compilar codereview vea [ codereview ].
CXX = clang++
CXX_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow
# Final binary
BIN = mybin
# Put all auto generated stuff to this build dir.
BUILD_DIR = ./build
# List of all .cpp source files.
CPP = main.cpp $(wildcard dir1/*.cpp) $(wildcard dir2/*.cpp)
# All .o files go to build dir.
OBJ = $(CPP:%.cpp=$(BUILD_DIR)/%.o)
# Gcc/Clang will create these .d files containing dependencies.
DEP = $(OBJ:%.o=%.d)
# Default target named after the binary.
$(BIN) : $(BUILD_DIR)/$(BIN)
# Actual target of the binary - depends on all .o files.
$(BUILD_DIR)/$(BIN) : $(OBJ)
# Create build directories - same structure as sources.
mkdir -p $(@D)
# Just link all the object files.
$(CXX) $(CXX_FLAGS) $^ -o $@
# Include all .d files
-include $(DEP)
# Build target for every single object file.
# The potential dependency on header files is covered
# by calling `-include $(DEP)`.
$(BUILD_DIR)/%.o : %.cpp
mkdir -p $(@D)
# The -MMD flags additionaly creates a .d file with
# the same name as the .o file.
$(CXX) $(CXX_FLAGS) -MMD -c $< -o $@
.PHONY : clean
clean :
# This should remove all generated files.
-rm $(BUILD_DIR)/$(BIN) $(OBJ) $(DEP)
Este método funciona porque si hay varias líneas de dependencia para un solo objetivo, las dependencias simplemente se unen, por ejemplo:
a.o: a.h
a.o: a.c
./cmd
es equivalente a:
a.o: a.c a.h
./cmd
como se menciona en: Makefile líneas de dependencia múltiples para un solo objetivo?
La solución de Martin anterior funciona muy bien, pero no maneja archivos .o que residen en subdirectorios. Godric señala que la bandera -MT se encarga de ese problema, pero evita simultáneamente que el archivo .o se escriba correctamente. Lo siguiente se encargará de ambos problemas:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) -o $@ $<
Lo siguiente funciona para mí:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.cpp
$(CXX) $(CFLAGS) -MMD -c -o $@ $<
Prefiero esta solución, sobre la respuesta aceptada por Michael Williamson, capta los cambios en las fuentes + archivos en línea, luego en las fuentes + encabezados y, finalmente, solo en las fuentes. La ventaja aquí es que no se vuelve a compilar toda la biblioteca si solo se realizan algunos cambios. No es una gran consideración para un proyecto con un par de archivos, pero si tiene 10 o 100 fuentes, notará la diferencia.
COMMAND= gcc -Wall -Iinclude ...
%.o: %.cpp %.inl
$(COMMAND)
%.o: %.cpp %.hpp
$(COMMAND)
%.o: %.cpp
$(COMMAND)
Si está utilizando un compilador de GNU, el compilador puede armar una lista de dependencias para usted. Fichero de Makefile:
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ -MF ./.depend;
include .depend
o
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ > ./.depend;
include .depend
donde SRCS
es una variable que apunta a su lista completa de archivos fuente.
También está la herramienta makedepend
, pero nunca me gustó tanto como gcc -MM