it-swarm.com.de

Wie kann ich ein Makefile automatisch Quelldateien erstellen lassen, die eine geänderte Headerdatei enthalten? (In C/C++)

Ich habe das folgende Makefile, das ich zum Erstellen eines Programms (eigentlich eines Kernels) verwende, an dem ich gerade arbeite. Es ist von Grund auf neu und ich lerne etwas über den Prozess, also ist es nicht perfekt, aber ich denke, es ist an dieser Stelle mächtig genug, um meine Erfahrung mit dem Schreiben von Makefiles zu machen.

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 [email protected] $^

$(SOBJS) : $(SFILES)
    $(AS) $(ASFLAGS) $< -o [email protected]

%.o: %.c
    @echo Compiling $<...
    $(CC) $(CFLAGS) -c -o [email protected] $<

#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 bei diesem Makefile ist, dass beim Ändern einer Headerdatei, die eine oder mehrere C-Dateien enthalten, die C-Dateien nicht neu erstellt werden. Ich kann dieses Problem leicht beheben, indem ich alle meine Header-Dateien als Abhängigkeiten für alle meine C-Dateien auswählt. Dies würde jedoch zu einer vollständigen Neuerstellung des Projekts führen, wenn ich eine Header-Datei ändere/hinzufügte.

Was ich will, ist, dass nur die C-Dateien, die include die Header-Datei, die ich ändere, neu erstellt werden, und dass das gesamte Projekt erneut verknüpft wird. Ich kann die Verknüpfung durchführen, indem ich alle Header-Dateien als Abhängigkeiten des Ziels anführe, aber ich kann nicht herausfinden, wie die C-Dateien für ungültig erklärt werden, wenn ihre enthaltenen Header-Dateien neuer sind.

Ich habe gehört, dass GCC einige Befehle hat, um dies zu ermöglichen (so dass das Makefile irgendwie herausfinden kann, welche Dateien neu erstellt werden müssen), aber ich kann für mein Leben kein reales Implementierungsbeispiel finden. Kann jemand eine Lösung posten, die dieses Verhalten in einem Makefile ermöglicht?

EDIT: Ich sollte klarstellen, ich bin mit dem Konzept vertraut, die einzelnen Ziele einzufügen und jedes Ziel festzulegen. Die Header-Dateien werden benötigt. Das erfordert, dass ich das Makefile jedes Mal editiere, wenn ich irgendwo eine Header-Datei einfüge, was ein bisschen schmerzhaft ist. Ich bin auf der Suche nach einer Lösung, die die Abhängigkeiten der Header-Datei selbst herleiten kann. Ich bin mir ziemlich sicher, dass ich sie in anderen Projekten gesehen habe.

83
Nicholas Flynt

Wie bereits an anderer Stelle auf dieser Website erwähnt, siehe diese Seite: http://make.paulandlesley.org/autodep.html

Kurz gesagt, kann gcc automatisch .d-Abhängigkeitsdateien für Sie erstellen. Hierbei handelt es sich um Mini-Makefile-Fragmente mit den Abhängigkeiten der von Ihnen kompilierten .c-Datei. Jedes Mal, wenn Sie die .c-Datei ändern und kompilieren, wird die .d-Datei erstellt bleibe auf dem Laufenden.

Neben dem Hinzufügen des -M-Flags zu gcc müssen Sie die .d-Dateien in das Makefile aufnehmen (wie oben von Chris beschrieben). Es gibt einige kompliziertere Probleme auf der Seite, die mit sed gelöst werden, aber Sie können dies Ignorieren Sie sie und machen Sie ein "sauber machen", um die .d-Dateien zu löschen, wenn Sie sich beschweren, dass Sie keine Header-Datei erstellen können, die nicht mehr vorhanden ist.

28
Udi Meiri

Sie können einen Befehl zum Erstellen von Abhängigkeiten hinzufügen, wie andere bereits angegeben haben. Warum sollten Sie aber nicht, dass gcc Abhängigkeiten erstellt und gleichzeitig kompiliert:

DEPS := $(COBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,[email protected]) -o [email protected] $<

Der Parameter '-MF' gibt eine Datei an, in der die Abhängigkeiten gespeichert werden sollen.

Der Bindestrich am Anfang von '-include' weist Make an, fortzufahren, wenn die D-Datei nicht vorhanden ist (z. B. beim ersten Kompilieren).

Beachten Sie, dass es in gcc einen Fehler in Bezug auf die Option -o gibt. Wenn Sie für den Objektnamen obj/_file__c.o angeben, enthält der generierte _file_.d weiterhin _file_.o, nicht obj/_file_c.o.

20
Martin Fido

Dies ist äquivalent zu Chris Dodds Antwort , verwendet jedoch eine andere Benennungskonvention (und erfordert zufällig nicht die sed-Magie. Kopieren von ein späteres Duplikat .


Wenn Sie einen GNU - Compiler verwenden, kann der Compiler eine Liste von Abhängigkeiten für Sie erstellen. Makefile-Fragment:

depend: .depend

.depend: $(SOURCES)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^>>./.depend;

include .depend

Es gibt auch das Tool makedepend, das mir aber nie so gut gefallen hat wie gcc -MM

16
dmckee

Sie müssen für jede C-Datei individuelle Ziele festlegen und dann die Header-Datei als Abhängigkeit auflisten. Sie können immer noch Ihre generischen Ziele verwenden und die .h-Abhängigkeiten danach einfach einfügen, wie folgt:

%.o: %.c
        @echo Compiling $<...
        $(CC) $(CFLAGS) -c -o [email protected] $<

foo.c: bar.h
# And so on...
7
mipadi

Über das, was @mipadi gesagt hat, können Sie auch die Verwendung der Option '-M' erkunden, um einen Datensatz der Abhängigkeiten zu generieren. Sie können diese sogar in einer separaten Datei erzeugen (vielleicht 'depend.mk'), die Sie dann in das Makefile aufnehmen. Oder Sie finden eine 'make depend'-Regel, die das Makefile mit den richtigen Abhängigkeiten bearbeitet (Google-Begriffe: "Diese Zeile nicht entfernen" und abhängig). 

3

Grundsätzlich müssen Sie die Makefile-Regeln dynamisch erstellen, um die Objektdateien neu zu erstellen, wenn sich die Header-Dateien ändern. Wenn Sie gcc und gnumake verwenden, ist dies ziemlich einfach. stell einfach so etwas wie:

$(OBJDIR)/%.d: %.c
        $(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >[email protected]

ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif

in deinem makefile.

3
Chris Dodd

Einfachere Lösung: Verwenden Sie einfach das Makefile, damit die Kompilierungsregel .c von .o von der Header-Datei (den Header-Dateien) abhängt und was sonst noch in Ihrem Projekt relevant ist.

Zum Beispiel im Makefile irgendwo:

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 [email protected] $<
0
Richard Elkins

Keine der Antworten funktionierte für mich. Z.B. Die Antwort von Martin Fido legt nahe, dass gcc eine Abhängigkeitsdatei erstellen kann, aber als ich versuchte, leere Objektdateien (null Bytes) zu generieren, ohne Warnungen oder Fehler. Es könnte ein Gcc-Fehler sein. ich bin on 

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

Also hier ist mein komplettes Makefile, das für mich funktioniert; Es handelt sich um eine Kombination von Lösungen + etwas, das von niemandem erwähnt wurde (z. B. "Suffix-Ersetzungsregel"), das als .cc.o angegeben wird :):

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,[email protected]) $<
    $(CC) $(CFLAGS) $(INCLUDES) -c -o [email protected] $<

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 Wichtigkeit dieser beiden Zeilen:

$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,[email protected]) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o [email protected] $<

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

0
Tagar