Wie bringe ich Makefile dazu, nur geänderte Dateien neu zu kompilieren?

Lesezeit: 8 Minuten

Benutzeravatar von Pithikos
Pithikos

Ich habe mich ein wenig bemüht, make dazu zu bringen, nur die Dateien zu kompilieren, die bearbeitet wurden. Allerdings hatte ich nicht viel Erfolg und alle Dateien werden neu kompiliert. Kann mir jemand erklären warum?

Meine Dateien sind:

main.c
a_functions.c

wo Haupt c beinhaltet main.h
und a_funktionen.c beinhaltet Ah

Hier ist mein Makefile:

CC=gcc
CFLAGS=-Wall -I. -c
EXEC_FILE=program1


all: program

a_functions.o: a_functions.c
a_functions.c: a.h
main.o: main.c
main.c: main.h

objects: a_functions.c main.c
    $(CC) a_functions.c main.c $(CFLAGS)

program: a_functions.o main.o
    $(CC) a_functions.o main.o -o $(EXEC_FILE)

Das Ändern des Makefiles gemäß den Vorschlägen scheint das gleiche Problem zu haben:

all: program

a_functions.o: a_functions.c a.h
    gcc a_functions.c -c

main.o: main.c main.h
    gcc main.c -c

program: a_functions.o main.o
    gcc a_functions.o main.o -o program1

  • -I. kommt mir seltsam vor. Was ist damit?

    – Sarnold

    19. Oktober 2011 um 0:56 Uhr

  • @sarnold: bedeutet nur Suche nach Include-Dateien im aktuellen Verzeichnis sowie nach implementierungsdefinierten. Ob es nötig ist, ist fraglich, aber ich glaube nicht, dass es schaden würde.

    – paxdiablo

    19. Oktober 2011 um 0:58 Uhr


  • @paxdiablo vielleicht, aber ich vermute, es ist ein Symptom für ein anderes Problem. Wenn seine Plattform keine systemweiten Header für etwas bereitstellt und er seine eigenen Versionen bereitstellen muss, ist das eine Sache, aber ich schätze, es ist so wie es ist ein Fehler …

    – Sarnold

    19. Oktober 2011 um 1:02 Uhr

  • @sarnold: Wie kann das ein Fehler sein? Es wird mit ziemlicher Sicherheit Header-Dateien geben, die in so ziemlich jedem Programm, das Sie jemals kompilieren möchten, in das aktuelle Verzeichnis aufgenommen werden müssen.

    – Famarri

    19. Oktober 2011 um 1:04 Uhr

  • Es ist keine gute Idee, Fragen so zu ändern, dass die Antworten ungültig werden. Fühlen sich frei vermehren Die Informationen (siehe meine Bearbeitung) sonst wird SO viel weniger nützlich, da die Antworten nicht mit den Fragen übereinstimmen.

    – paxdiablo

    19. Oktober 2011 um 1:32 Uhr

Benutzeravatar von Beta
Beta

Das spezifische Problem, von dem Sie sprechen — Machen Sie Neuerstellungen program1 (durch Neuverknüpfung der Objekte) auch wenn sich nichts geändert hat — ist in dieser Regel:

program: a_functions.o main.o
    gcc a_functions.o main.o -o program1

Das Ziel dieser Regel ist program, und Make geht davon aus, dass es sich um eine Datei handelt. Aber da es keine solche Datei gibt, denkt Make jedes Mal, wenn Sie Make ausführen, dass diese Datei neu erstellt werden muss, und führt die Regel aus. Ich schlage vor:

program1: a_functions.o main.o
    gcc a_functions.o main.o -o program1

Oder besser das:

program1: a_functions.o main.o
    gcc $^ -o [email protected]

Oder besser noch das:

$(EXEC_FILE): a_functions.o main.o
    $(CC) $^ -o [email protected]

(Und vergessen Sie nicht, die zu ändern all Regel zu entsprechen.)

Noch ein paar Punkte:

  1. Wie @paxdiablo betonte,

    a_functions.o: a_functions.c a.h
    main.o: main.c main.h
    
  2. Es macht keinen Sinn, diese Objekte miteinander zu verknüpfen, es sei denn, etwas in einem (wahrscheinlich main.o) ruft etwas im anderen (wahrscheinlich a_functions.o), also würde ich erwarten, eine Abhängigkeit wie diese zu sehen:

    main.o: a.h
    

    Ich vermute also, dass Sie einige unangebrachte Erklärungen haben.

  3. Du erklärst ein objects Regel, aber beziehen Sie sich nie darauf. Sie verwenden es also nie wirklich; Make verwendet die Standardregel für %.o: %.c. Ich schlage vor:

    OBJECTS = a_functions.o main.o
    $(OBJECTS): %.o: %.c
        $(CC) $< $(CFLAGS) -o [email protected]
    

    (In diesem Fall können Sie ändern $(EXEC_FILE): a_functions.o main.o zu $(EXEC_FILE): $(OBJECTS).) Oder einfach so:

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

  • Guter Fang, +1, ich denke, wir haben einen Gewinner.

    – paxdiablo

    19. Oktober 2011 um 3:29 Uhr

  • Hätte .PHONY geholfen? (Wahrscheinlich aber ein GNU-Make-Only-Feature.)

    – David Poole

    24. Oktober 2011 um 20:55 Uhr

  • @DavidPoole, konzeptionell ja, es würde Make that sagen program wird nicht als Datei erwartet (und sollte ausgeführt werden, selbst wenn eine solche Datei existiert). Praktisch nein, da Make diese Regel immer noch ausführen würde, selbst wenn sich nichts geändert hätte.

    – Beta

    25. Oktober 2011 um 3:11 Uhr

  • Vielen Dank. Ich sehe jetzt wie $(OBJECTS): %.c macht keinen Sinn. Also die Regel %.o: %.c<newline><TAB>$(CC) $< $(CFLAGS) -o [email protected] bedeutet “für jede .c-Datei die entsprechende .o-Objektdatei kompilieren”. Und die Regel $(OBJECTS): %: %.c<newline><TAB>$(CC) $< $(CFLAGS) -o [email protected] bedeutet “für jede .o-Datei in OBJECTS kompilieren Sie die entsprechende .c-Datei in eine .o-Objektdatei”.(?) – Ich bemerke eine Diskrepanz zwischen Ihrer $(OBJECTS): %: %.c und die $(objects): %.o: %.c in die Dokumente – Sie schreiben %.o wo du nur schreibst %. Schreibfehler? Oder beide gültig?

    – Henke

    8. Dezember 2020 um 10:14 Uhr


  • @Henke: Guter Fang, das war ein Tippfehler von mir — der neun Jahre lang niemandem aufgefallen ist! Ich werde bearbeiten.

    – Beta

    8. Dezember 2020 um 15:53 ​​Uhr

Benutzeravatar von paxdiablo
paxdiablo

Nicht sicher, ob dies Ihr spezifisches Problem verursacht, aber die beiden Zeilen:

a_functions.c: a.h
main.c: main.h

sind definitiv falsch, da es im Allgemeinen keinen Befehl gibt, um eine C-Datei basierend auf einem darin enthaltenen Header neu zu erstellen.

C-Dateien hängen nicht von ihren Header-Dateien ab, die Objekte erstellt von diesen C-Dateien tun.

Zum Beispiel ein main.c von:

#include <hdr1.h>
#include <hdr2.h>
int main (void) { return 0; }

wäre im makefile als etwas wie:

main.o: main.c hdr1.h hdr2.h
    gcc -c -o main.o main.c

Veränderung:

a_functions.o: a_functions.c
a_functions.c: a.h
main.o: main.c
main.c: main.h

zu:

a_functions.o: a_functions.c a.h
main.o: main.c main.h

(vorausgesetzt, dass a_functions.c beinhaltet a.h und main.c beinhaltet main.h) und versuche es noch mal.

Wenn diese obige Annahme falsch ist, müssen Sie uns mitteilen, welche C-Dateien welche Header enthalten, damit wir Ihnen die richtigen Regeln mitteilen können.


Wenn Ihre Behauptung ist, dass die makefile auch nach diesen Änderungen immer noch alles baut, müssen Sie sich zwei Dinge ansehen.

Die erste ist die Ausgabe von ls -l auf alle relevanten Dateien, damit Sie sehen können, welche Daten und Uhrzeiten sie haben.

Die zweite ist die tatsächliche Ausgabe von make. Die Ausgabe von make -d wird da besonders hilfreich sein zeigt an welche Dateien und Daten make verwendet, um herauszufinden, was zu tun ist.


In Bezug auf die Untersuchung, make scheint nach folgendem Transkript gut zu funktionieren:

=====
pax$ cat qq.h
#define QQ 1
=====
pax$ cat qq.c
#include "qq.h"
int main(void) { return 0; }
=====
pax$ cat qq.mk
qq: qq.o
        gcc -o qq qq.o

qq.o: qq.c qq.h
        gcc -c -o qq.o qq.c
=====
pax$ touch qq.c qq.h
=====
pax$ make -f qq.mk
gcc -c -o qq.o qq.c
gcc -o qq qq.o
=====
pax$ make -f qq.mk
make: `qq' is up to date.

  • Ich habe getan, wie Sie gesagt haben, aber es wird immer noch alles neu kompiliert. Ich habe sogar versucht, Ihr Beispiel zu kopieren, indem ich main.o: main.c main.h \n $(CC) main.c $(CFLAGS) hatte, aber immer noch das gleiche Problem

    – Pithikos

    19. Oktober 2011 um 1:11 Uhr

  • @Pithikos: Zeigen Sie uns die Ausgabe des Compilers. Warum sagen Sie, dass es jedes Mal kompiliert wird.

    – Famarri

    19. Oktober 2011 um 1:20 Uhr

  • @Falmarri Ich kann sehen, dass es neu kompiliert wird, wenn sich das Datum von program1 jedes Mal ändert, wenn ich es mache.

    – Pithikos

    19. Oktober 2011 um 1:24 Uhr

  • Die Objekte werden nicht neu kompiliert. Es ist nur das Programm1, das neu verknüpft wird.

    – Pithikos

    19. Oktober 2011 um 1:40 Uhr

Benutzeravatar von Owl
Eule

Dies sehr spät nach der Tatsache, und eigentlich basiert es auf der hervorragenden Antwort von paxdiablo, aber beim Experimentieren habe ich festgestellt, dass Sie keine separaten Ziele für jede .o-Datei benötigen, es sei denn, Sie tun etwas Cleveres.

Also für mein Makefile:

all: program

program: a_functions.o main.o
    gcc a_functions.o main.o -o program

clean: 
    rm -f *.o
    rm -f program

In make 4.1 werden die .o-Dateien automatisch kompiliert, Sie müssen nichts tun, wenn Ihre .o-Dateien dieselben Namen haben wie Ihre Quelldateien. Also wird es automatisch nach a_functions.c, a_functions.h, main.h und main.c suchen. Wenn Sie nicht die erwarteten Quellcodenamen haben, erhalten Sie eine Fehlermeldung wie:

make: *** No rule to make target 'a_functions.o', needed by 'program'.  Stop.

Ich habe auch ein “sauberes” Ziel für Sie hinzugefügt. “Clean” ist nützlich, wenn Sie Ihre Software als Quellcode freigeben müssen oder einfach alle kompilierten Objektdateien und / oder Binärdateien entfernen möchten.

Und das ist alles, was Sie tun müssen.

Speichern Sie dies in “Makefile” und führen Sie Folgendes aus:

$ make

um Ihre Binärdatei zu erstellen. Und

$ make clean 

um die kompilierten Objekte und Binärdateien in Ihrem Code zu bereinigen.

1417740cookie-checkWie bringe ich Makefile dazu, nur geänderte Dateien neu zu kompilieren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy