Autor Thema: Makefile Magie ;)  (Gelesen 9023 mal)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« am: 15. February 2012, 21:12 »
Ich baue meine Sources gerade so um, dass ich meinen Kernel (und dann das ganze OS) auf andere Architekturen portieren kann.

In meinem Makefile habe ich eine Variable "SRCS" wo meine ganzen Source-Dateien drin stehen. Aus dieser Liste habe ich vorher einfach durch ersetzen der Endung eine Liste von Object-Dateien gemacht. Nun müssen aber einige Einträge der Liste um die Verzeichnisse bereinigt werden, was auch kein Problem war (wird über die Hilfsvariable "TEMP" gemacht). Nur kompiliert er jetzt genau diese Dateien nicht. Obwohl die entsprechenden Regeln dafür vorhanden sind.

Mein Makefile:
CXXFLAGS = -O2 -Wall -Wextra -fno-use-cxa-atexit -fno-stack-protector -fno-rtti -fno-exceptions -fno-asynchronous-unwind-tables -fno-builtin -march=i586 -I$(PREFIX)include -I../../../../../include -fno-common
CXXFLAGS += -DX86_32
LDFLAGS = -nostdlib -T$(LINKERSCRIPT) -i
PREFIX = ../../../../src/
PLATFORM = platform/x86_32/
SRCS = $(PLATFORM)kernel.cpp string.cpp $(PLATFORM)exceptions.cpp $(PLATFORM)idt.cpp $(PLATFORM)video.cpp debug.cpp $(PLATFORM)vmm.cpp
SRCS += $(PLATFORM)vmmAddrSpace.cpp slab.cpp map.cpp avl.cpp $(PLATFORM)pmm.cpp list.cpp $(PLATFORM)cpu.cpp $(PLATFORM)gdt.cpp
SRCS += $(PLATFORM)tss.cpp patriciatree.cpp array.cpp $(PLATFORM)syscall.cpp semaphore.cpp $(PLATFORM)scheduler.cpp
SRCS += $(PLATFORM)task.cpp $(PLATFORM)thread.cpp port.cpp
TEMP = $(subst $(PLATFORM),,$(SRCS))
OBJS = $(TEMP:%.cpp=%.o) exceptions-asm.o scheduler-asm.o
DEPENDFILE = .depend
LINKERSCRIPT = ../kernel.ld
VPATH = $(PREFIX)

.PHONY: all clean

all: $(DEPENDFILE) kernel.ko

$(DEPENDFILE): $(SRCS:%=$(PREFIX)%)
$(CXX) -M $(SRCS:%=$(PREFIX)%) $(CXXFLAGS) > $(DEPENDFILE)

-include $(DEPENDFILE)

exceptions-asm.o: $(PREFIX)$(PLATFORM)exceptions.asm
nasm -O3 $(PREFIX)$(PLATFORM)exceptions.asm -f elf -o exceptions-asm.o
scheduler-asm.o: $(PREFIX)$(PLATFORM)scheduler.asm
nasm -O3 $(PREFIX)$(PLATFORM)scheduler.asm -f elf -o scheduler-asm.o
   
kernel.ko: $(OBJS) $(LINKERSCRIPT)
$(LD) $(OBJS) -o kernel.ko $(LDFLAGS)
cp kernel.ko ../

clean:
-rm -f kernel.ko
-rm -f *.o
-rm -f *.s
-rm -f $(DEPENDFILE)

Folgender Ausschnitt aus meiner ".depend"-Datei sieht auch ok aus (die ganze passte nicht in den Beitrag):
kernel.o: ../../../../src/platform/x86_32/kernel.cpp \
 ../../../../src/include/panic.hpp ../../../../../include/typedef.h \
 ../../../../../include/compiler.h \
 ../../../../src/include/loader-strucs.hpp \
 ../../../../src/include/platform/x86_32/loader-strucs.hpp \
 ../../../../src/include/platform/x86_32/irq/ioapic.hpp \
 ../../../../src/include/video.hpp \
 ../../../../src/include/platform/x86_32/video.hpp \
 ../../../../src/include/exceptions.hpp \
 ../../../../src/include/platform/x86_32/exceptions.hpp \
 ../../../../src/include/debug.hpp ../../../../src/include/pmm.hpp \
 ../../../../src/include/platform/x86_32/pmm.hpp \
 ../../../../src/include/vmm.hpp \
 ../../../../src/include/platform/x86_32/vmm.hpp \
 ../../../../src/include/spinlock.hpp \
 ../../../../src/include/platform/x86_32/spinlock.hpp \
 ../../../../src/include/map.hpp ../../../../src/include/avl.hpp \
 ../../../../src/include/list.hpp ../../../../src/include/slab.hpp \
 ../../../../src/include/memory.hpp \
 ../../../../src/include/platform/x86_32/memory.hpp \
 ../../../../src/include/kernel.hpp \
 ../../../../src/include/platform/x86_32/kernel.hpp \
 ../../../../src/include/cpu.hpp \
 ../../../../src/include/platform/x86_32/cpu.hpp \
 ../../../../src/include/asm.hpp \
 ../../../../src/include/platform/x86_32/asm.hpp \
 ../../../../src/include/irq.hpp \
 ../../../../src/include/platform/x86_32/irq.hpp \
 ../../../../src/include/fpu.hpp \
 ../../../../src/include/platform/x86_32/fpu.hpp \
 ../../../../src/include/timer.hpp \
 ../../../../src/include/patriciatree.hpp \
 ../../../../src/include/rwlock.hpp \
 ../../../../src/include/platform/x86_32/rwlock.hpp \
 ../../../../src/include/syscall.hpp \
 ../../../../src/include/platform/x86_32/syscall.hpp \
 ../../../../src/include/semaphore.hpp ../../../../src/include/os.hpp \
 ../../../../src/include/array.hpp ../../../../src/include/task.hpp \
 ../../../../src/include/platform/x86_32/task.hpp \
 ../../../../src/include/thread.hpp \
 ../../../../src/include/platform/x86_32/thread.hpp \
 ../../../../src/include/atomic.hpp \
 ../../../../src/include/platform/x86_32/atomic.hpp \
 ../../../../src/include/scheduler.hpp \
 ../../../../src/include/platform/x86_32/tss.hpp \
 ../../../../src/include/port.hpp \
 ../../../../src/include/platform/x86_32/cpu/smp.hpp \
 ../../../../src/include/platform/x86_32/timer/rtc.hpp \
 ../../../../src/include/platform/x86_32/idt.hpp
string.o: ../../../../src/string.cpp ../../../../src/include/string.hpp \
 ../../../../../include/typedef.h ../../../../../include/compiler.h
Die "string.cpp" wird kompiliert, aber nicht die "kernel.cpp". Kann sich jemand denken wieso? Ich bekomme auch keine Fehlermeldung oder so (erst wenn ld versucht alle Object-Dateien zusammen zu linken).

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 15. February 2012, 21:48 »
Das Problem ist, dass keine Regel existiert, die Source-Dateien in $(PLATFORM) in Objektdateien nach . kompiliert. Also sowas wie zum Beispiel das hier:
%.o: $(PREFIX)$(PLATFORM)/%.cpp
g++ -o $@ $<

Es ist keine Fehlermeldung ausgegeben worden, weil die leeren Regeln aus der .depend-Datei (kernel.o: ../../../../src/platform/x86_32/kernel.cpp usw...) auch die Dependencies von kernel.ko erfüllen.
« Letzte Änderung: 15. February 2012, 21:50 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 15. February 2012, 21:54 »
Zitat von: Jidder
Das Problem ist, dass keine Regel existiert, die Source-Dateien in $(PLATFORM) in Objektdateien nach . kompiliert. Also sowas wie zum Beispiel das hier:
Hmm, ich dachte die erste Regel entspricht in etwa genau deinem Bsp.?!

Zitat von: Jidder
Es ist keine Fehlermeldung ausgegeben worden, weil die leeren Regeln aus der .depend-Datei (kernel.o: ../../../../src/platform/x86_32/kernel.cpp usw...) auch die Dependencies von kernel.ko erfüllen.
Da kann ich dir gerade gar nicht folgen.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 15. February 2012, 22:13 »
Hmm, ich dachte die erste Regel entspricht in etwa genau deinem Bsp.?!
Welche meinst du? Die in der .depend-Datei? Die gibt nur die Abhängigkeit an, allerdings matcht die Regel nicht das Pattern, das normalerweise für das Kompilieren von .cpp-Dateien nach .o-Dateien verwendet wird. Deswegen wird der Compiler nicht aufgerufen.

Zitat von: Jidder
Es ist keine Fehlermeldung ausgegeben worden, weil die leeren Regeln aus der .depend-Datei (kernel.o: ../../../../src/platform/x86_32/kernel.cpp usw...) auch die Dependencies von kernel.ko erfüllen.
Da kann ich dir gerade gar nicht folgen.
Vielleicht hilft das: Ich hab mir um meine Theorie zu testen folgende Makefile gebaut.

all: kernel.ko

VPATH=fl

kernel.ko: kernel.o string.o
$(CXX) -o $@ $+

kernel.o: fl/platform/kernel.cpp
string.o:

clean:
$(RM) kernel.ko string.o kernel.o

%.o: fl/platform/%.cpp
g++ -o $@ $<

(Um Variablen zu sparen ist fl dein $(PREFIX), und platform dein $(PLATFORM). Die Dateien ./fl/platform/kernel.cpp und ./string.cpp existieren.)

Die beiden Zeilen mit kernel.o und string.o am Anfang stellen den Inhalt von .depend dar. Ich hab mal auf Header verzichtet, weil die nicht relevant für das Problem sind, aber die würden da natürlich auch noch stehen.

Wenn make jetzt die Abhängigkeiten von kernel.ko untersucht, findet es diese beiden Regeln und außerdem hat es noch diese implizite Regel in der Datenbank (kannste dir mit make -p ausgeben lassen), um C++-Dateien zu kompilieren:
%.o: %.cpp
#  commands to execute (built-in):
$(COMPILE.cpp) $(OUTPUT_OPTION) $<

Wenn make jetzt string.o bauen will matcht die Regel aus der .depend-Datei und die built-in-Regel. Die eine ist für die Abhängigkeiten und die andere für den Compileraufruf.
Wenn hingegen kernel.o gebaut werden soll, matcht die built-in-Regel nicht weil der %-Operator ja erwarten würde, dass die .cpp-Datei im aktuellen Verzeichnis liegt. Nur die Regel aus der .depend-Datei matcht, und damit sieht make seine Arbeit getan, weil make denkt, dass kernel.o keine Datei ist, sondern eine Aktion darstellt (wie all oder clean).

Zum Testen: Du kannst dir anschauen, was make denkt, wenn du -d als Parameter übergibst. Das sind allerdings ziemlich viele Ausgaben aufgrund der built-in-Regeln. Du kannst diese mit dem weiteren Parameter -r deaktivieren. Dann fehlt natürlich wieder die Regel für %.o: %.cpp, die du einfach auch noch in die Makefile schreibst:
%.o: %.cpp
$(COMPILE.cpp) $(OUTPUT_OPTION) $<

Der Unterschied ist, dass make ohne die zusätzliche Regel für Sourcen in $(PLATFORM) folgendes ausgibt:
    Must remake target `kernel.o'.
    Successfully remade target file `kernel.o'.
Aber mit der Regel führt es den GCC aus:
    Must remake target `kernel.o'.
g++    -c -o kernel.o fl/platform/kernel.cpp
Putting child 0x0a01c2b0 (kernel.o) PID 4112 on the chain.
Live child 0x0a01c2b0 (kernel.o) PID 4112
Reaping winning child 0x0a01c2b0 PID 4112
Removing child 0x0a01c2b0 PID 4112 from chain.
    Successfully remade target file `kernel.o'.
Ich hoffe das verwirrt jetzt nicht noch mehr ^^
« Letzte Änderung: 15. February 2012, 22:25 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 16. February 2012, 17:59 »
Wow, jetzt bin ich noch mehr verwirrt ;)

Ich dachte bisher das die Abhängigkeiten auch gleichzeitig das "Rezept" zum Kompilien sind. Sprich in der Form "AUSGABE_DATEI: SOURCE_DATEI [ABHÄNGIGKEITEN]".

Also scheine ich make nicht wirklich verstanden zu haben. Anders gefragt, wie könnte ich denn mein Problem lösen? Im Moment denke ich einfach nur, wieso ist make so blöd ;)

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 16. February 2012, 19:29 »
Ich dachte bisher das die Abhängigkeiten auch gleichzeitig das "Rezept" zum Kompilien sind. Sprich in der Form "AUSGABE_DATEI: SOURCE_DATEI [ABHÄNGIGKEITEN]".
Nur die Auflistung der Abhängigkeiten reicht nicht. Deswegen hat Make ja die built-in-Regeln, die die Rezepte enthalten. Normalerweise reichen diese Regeln auch, weil die Quelldateien im selben Verzeichnis wie die Objektdateien liegen. In deinem Fall liegen die Plattformdateien aber woanders, und die built-in-Regel kommt nicht zur Anwendung.

Die eine Lösung wäre eine zusätzliche Regel einzuführen, die analog zur built-in-Regel die Plattformdateien kompiliert:
%.o: $(PREFIX)$(PLATFORM)/%.cpp
g++ -o $@ $<

Was vielleicht auch funktionieren könnte, wäre den PLATFORM-Pfad zusätzlich in den VPATH aufzunehmen. Das ist allerdings nur Spekulation meinerseits, weil ich um VPATH lieber einen Bogen mache. Es könnten dann weitere Probleme auftreten, falls in beiden Verzeichnissen Dateien mit dem selben Namen liegen.
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 16. February 2012, 19:43 »
Zitat von: Jidder
Die eine Lösung wäre eine zusätzliche Regel einzuführen, die analog zur built-in-Regel die Plattformdateien kompiliert:
Interessant, werde ich dann mal ausprobieren.

Zitat von: Jidder
Was vielleicht auch funktionieren könnte, wäre den PLATFORM-Pfad zusätzlich in den VPATH aufzunehmen. Das ist allerdings nur Spekulation meinerseits, weil ich um VPATH lieber einen Bogen mache. Es könnten dann weitere Probleme auftreten, falls in beiden Verzeichnissen Dateien mit dem selben Namen liegen.
Hmm, ich habe im VPATH ja schon das Source-Verzeichnis drin, kann man da mehrere Verzeichnisse reinpacken? An doppelten Dateinamen sollte es nicht hapern.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 16. February 2012, 19:45 »
Hmm, ich habe im VPATH ja schon das Source-Verzeichnis drin, kann man da mehrere Verzeichnisse reinpacken? An doppelten Dateinamen sollte es nicht hapern.

Ja. Das Trennzeichen ist Doppelpunkt oder Leerzeichen.
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 17. February 2012, 21:27 »
Thx, das mit dem VPATH hat wunderbar funktioniert :D

 

Einloggen