Makefile, dependencias de encabezado
Digamos que tengo un archivo MAKE con la regla
%.o: %.c
gcc -Wall -Iinclude ...
Quiero que *.o se reconstruya cada vez que cambie un archivo de encabezado. En lugar de elaborar una lista de dependencias, cada vez que /include
cambia un archivo de encabezado, se deben reconstruir todos los objetos en el directorio.
No se me ocurre una buena manera de cambiar la regla para adaptarse a esto, estoy abierto a sugerencias. Puntos de bonificación si la lista de encabezados no tiene que estar codificada
Si está utilizando un compilador GNU, el compilador puede compilar una lista de dependencias por usted. Fragmento de archivo Make:
depend: .depend
.depend: $(SRCS)
rm -f "$@"
$(CC) $(CFLAGS) -MM $^ -MF "$@"
include .depend
o
depend: .depend
.depend: $(SRCS)
rm -f "$@"
$(CC) $(CFLAGS) -MM $^ > "$@"
include .depend
¿Dónde SRCS
hay una variable que apunta a su lista completa de archivos fuente?
También está la herramienta makedepend
, pero nunca me gustó tanto comogcc -MM
La mayoría de las respuestas son sorprendentemente complicadas o erróneas. Sin embargo, se han publicado ejemplos simples y sólidos en otros lugares [ 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 destino de compilación -MM
está documentada y no es un error [ gpp ]:
De forma predeterminada, CPP toma el nombre del archivo de entrada principal, elimina cualquier componente del directorio y cualquier sufijo de archivo como '.c' y agrega el sufijo de objeto habitual de la plataforma.
La -MMD
opción (algo más nueva) es probablemente lo que desea. Para completar, un ejemplo de un archivo MAKE que admite múltiples directorios src y directorios de compilación con algunos comentarios. Para obtener una versión simple sin directorios de compilación, consulte [ 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 único 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 varias líneas de dependencia para un solo objetivo?