Makefile, dependencias de encabezado

Resuelto Mike asked hace 14 años • 10 respuestas

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 /includecambia 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

Mike avatar Mar 07 '10 07:03 Mike
Aceptado

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 SRCShay 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 -MMestá 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 -MMDopció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?

Sophie avatar May 09 '2015 16:05 Sophie