101 Stimmen

Wie kann ich ein Makefile veranlassen, Quelldateien, die eine geänderte Header-Datei enthalten, automatisch neu zu erstellen? (In C/C++)

Ich habe das folgende Makefile, das ich verwende, um ein Programm (eigentlich einen Kernel) zu erstellen, an dem ich gerade arbeite. Es wurde von Grund auf neu erstellt und ich lerne gerade etwas über den Prozess, daher ist es nicht perfekt, aber ich denke, dass es zu diesem Zeitpunkt leistungsfähig genug ist für meine Erfahrung beim Schreiben von Makefiles.

AS  =   nasm
CC  =   gcc
LD  =   ld

TARGET      =   core
BUILD       =   build
SOURCES     =   source
INCLUDE     =   include
ASM         =   assembly

VPATH = $(SOURCES)

CFLAGS  =   -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
            -nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS =   -f elf

#CFILES     =   core.c consoleio.c system.c
CFILES      =   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES      =   assembly/start.asm

SOBJS   =   $(SFILES:.asm=.o)
COBJS   =   $(CFILES:.c=.o)
OBJS    =   $(SOBJS) $(COBJS)

build : $(TARGET).img

$(TARGET).img : $(TARGET).elf
    c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img

$(TARGET).elf : $(OBJS)
    $(LD) -T link.ld -o $@ $^

$(SOBJS) : $(SFILES)
    $(AS) $(ASFLAGS) $< -o $@

%.o: %.c
    @echo Compiling $<...
    $(CC) $(CFLAGS) -c -o $@ $<

#Clean Script - Should clear out all .o files everywhere and all that.
clean:
    -del *.img
    -del *.o
    -del assembly\*.o
    -del core.elf

Mein Hauptproblem mit diesem Makefile ist, dass wenn ich eine Header-Datei ändere, die eine oder mehrere C-Dateien enthält, die C-Dateien nicht neu erstellt werden. Ich kann dies ganz einfach beheben, indem alle meine Header-Dateien sind Abhängigkeiten für alle meine C-Dateien, aber das würde effektiv dazu führen, dass ein komplettes Rebuild des Projekts jedes Mal, wenn ich geändert/hinzugefügt eine Header-Datei, die nicht sehr anmutig sein würde.

Was ich möchte, ist, dass nur die C-Dateien, die einschließen. die von mir geänderte Header-Datei neu erstellt und das gesamte Projekt neu verlinkt werden muss. Ich kann die Verknüpfung tun, indem ich alle Header-Dateien zu Abhängigkeiten des Ziels, aber ich kann nicht herausfinden, wie die C-Dateien ungültig gemacht werden, wenn ihre enthaltenen Header-Dateien neuer sind.

Ich habe gehört, dass GCC einige Befehle hat, um dies möglich zu machen (so dass das Makefile irgendwie herausfinden kann, welche Dateien neu erstellt werden müssen), aber ich kann nicht für das Leben von mir ein tatsächliches Beispiel für die Implementierung finden, um zu sehen. Kann jemand eine Lösung posten, die dieses Verhalten in einem Makefile ermöglicht?

EDIT: Ich sollte klarstellen, ich bin vertraut mit dem Konzept der Platzierung der einzelnen Ziele in und mit jeder target.o erfordern die Header-Dateien. Das erfordert, dass ich die makefile jedes Mal, wenn ich eine Header-Datei irgendwo einschließen, die ein bisschen ein Schmerz ist zu bearbeiten. Ich bin auf der Suche nach einer Lösung, die die Header-Datei-Abhängigkeiten auf eigene Faust ableiten kann, die ich bin ziemlich sicher, ich habe in anderen Projekten gesehen.

3voto

Jonathan Leffler Punkte 694013

Über das hinaus, was @mipadi gesagt hat, können Sie auch die Verwendung der ' -M ', um eine Aufzeichnung der Abhängigkeiten zu erstellen. Sie könnten diese sogar in einer separaten Datei (vielleicht 'depend.mk') erzeugen, die Sie dann in das Makefile einfügen. Oder Sie können eine ' make depend Regel, die das Makefile mit den korrekten Abhängigkeiten bearbeitet (Google-Begriffe: "Diese Zeile nicht entfernen" und depend).

3voto

Richard Elkins Punkte 317

Einfachere Lösung: Verwenden Sie einfach das Makefile, um die .c-zu-.o-Kompilierungsregel von der/den Header-Datei(en) und allem anderen, was in Ihrem Projekt als Abhängigkeit relevant ist, abhängig zu machen.

Z.B. irgendwo im Makefile:

DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv

::: (your other Makefile statements like rules 
:::  for constructing executables or libraries)

# Compile any .c to the corresponding .o file:
%.o: %.c $(DEPENDENCIES)
        $(CC) $(CFLAGS) -c -o $@ $<

0voto

Tagar Punkte 12059

Keine der Antworten hat bei mir funktioniert. Martin Fidos Antwort schlägt z.B. vor, dass gcc eine Abhängigkeitsdatei erstellen kann, aber als ich das ausprobiert habe, hat er leere (null Bytes) Objektdateien für mich erzeugt, ohne irgendwelche Warnungen oder Fehler. Es könnte ein Gcc-Bug sein. Ich bin auf

$ gcc --version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)

Hier ist also mein komplettes Makefile, das für mich funktioniert; es ist eine Kombination aus Lösungen + etwas, das von niemandem sonst erwähnt wurde (z.B. "Suffix-Ersetzungsregel", angegeben als .cc.o:):

CC = g++
CFLAGS = -Wall -g -std=c++0x
INCLUDES = -I./includes/

# LFLAGS = -L../lib
# LIBS = -lmylib -lm

# List of all source files
SRCS = main.cc cache.cc

# Object files defined from source files
OBJS = $(SRCS:.cc=.o)

# # define the executable file 
MAIN = cache_test

#List of non-file based targets:
.PHONY: depend clean all

##  .DEFAULT_GOAL := all

# List of dependencies defined from list of object files
DEPS := $(OBJS:.o=.d)

all: $(MAIN)

-include $(DEPS)

$(MAIN): $(OBJS)
    $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)

#suffix replacement rule for building .o's from .cc's
#build dependency files first, second line actually compiles into .o
.cc.o:
    $(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

clean:
    $(RM) *.o *~ $(MAIN) *.d

Beachten Sie, dass ich .cc verwendet habe. Das obige Makefile lässt sich leicht für .c-Dateien anpassen.

Beachten Sie auch die Bedeutung dieser beiden Zeilen:

$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

gcc wird also einmal aufgerufen, um zunächst eine Abhängigkeitsdatei zu erstellen, und kompiliert dann tatsächlich eine .cc-Datei. Und so weiter für jede Quelldatei.

-1voto

jdizzle Punkte 3753

Ich glaube, die mkdep Befehl ist das, was Sie wollen. Er durchsucht .c-Dateien nach #include Zeilen und erstellt für sie einen Abhängigkeitsbaum. Ich glaube, Automake/Autoconf-Projekte verwenden dies standardmäßig.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X