Im letzten Jahr habe ich angefangen, in Fortran zu programmieren, während ich an einer Forschungsuniversität arbeitete. Die meisten meiner bisherigen Erfahrungen habe ich mit Websprachen wie PHP oder dem alten ASP gemacht, also bin ich ein Neuling, um Anweisungen zu kompilieren.
Ich habe zwei verschiedene Codes, die ich ändere.
Einer hat ein explizite Anweisung zum Erstellen von .o-Dateien aus Modulen (z. B. gfortran -c filea.f90), bevor Sie die ausführbare Datei erstellen.
Andere sind Erstellen der ausführbaren Datei direkt (manchmal .mod-Dateien erstellen, aber keine .o-Dateien, zB gfortran -o ausführbare Dateia.f90 Dateib.f90 Hauptdatei.f90).
Gibt es einen Grund (außer vielleicht Makefiles), dass eine Methode der anderen vorgezogen wird?
Im Allgemeinen verwenden wir obj-Dateien zum “Zwischenspeichern” der Kompilierung. Erleichtern Sie die Wiederverwendung von altem kompiliertem Code, um die Kompilierungszeit zu minimieren.
– Stefan
12. März 2011 um 16:44 Uhr
“Code” ist in diesem Zusammenhang ein nicht zählbares Substantiv; daher ist “zwei Codes” falsch.
– Leichtigkeitsrennen im Orbit
12. März 2011 um 17:28 Uhr
Die Verwendung von “Code” als Zählnomen für Programme und Bibliotheken ist eine leider übliche Verwendung unter Physikern. Es ist unwahrscheinlich, dass Korrekturen in dieser Gemeinschaft stattfinden.
– wnoise
13. März 2011 um 20:13 Uhr
@wnoise Aber wir werden es versuchen, verdammt noch mal. Wir werden es versuchen.
– AndyPerfekt
14. März 2011 um 19:10 Uhr
Ha, danke für die Korrektur. Ich hatte diese Programme nie “Codes” genannt, bis ich anfing, hier zu arbeiten.
– Tomshafer
14. März 2011 um 20:05 Uhr
kriss
Das Kompilieren zuerst in Objektdateien wird als separate Kompilierung bezeichnet. Es gibt viele Vorteile und ein paar Nachteile.
Vorteile:
Einfaches Umwandeln von Objektdateien (.o) in Bibliotheken und späteres Verknüpfen mit ihnen
Viele Personen können gleichzeitig an verschiedenen Quelldateien arbeiten
schnelleres Kompilieren (Sie kompilieren nicht immer wieder dieselben Dateien, wenn sich die Quelle nicht geändert hat)
Objektdateien können aus verschiedenen Sprachquellen erstellt und zu einem späteren Zeitpunkt miteinander verknüpft werden. Dazu müssen die Objektdateien lediglich dasselbe Format und kompatible Aufrufkonventionen verwenden.
Die separate Kompilierung ermöglicht die Verteilung von systemweiten Bibliotheken (entweder Betriebssystembibliotheken, Sprachstandardbibliotheken oder Bibliotheken von Drittanbietern), entweder statisch oder gemeinsam genutzt.
Nachteile:
Es gibt einige Optimierungen (wie das Optimieren von Funktionen), die der Compiler nicht durchführen kann, und der Linker kümmert sich nicht darum; Viele Compiler enthalten jetzt jedoch die Option, eine “Verbindungszeitoptimierung” durchzuführen, wodurch dieser Nachteil weitgehend aufgehoben wird. Dies ist jedoch immer noch ein Problem für Systembibliotheken und Bibliotheken von Drittanbietern, insbesondere für gemeinsam genutzte Bibliotheken (es ist unmöglich, Teile einer Komponente wegzuoptimieren, die sich bei jedem Lauf ändern können, andere Techniken wie die JIT-Kompilierung können dies jedoch abmildern).
In einigen Sprachen muss der Programmierer eine Art Header für die Verwendung anderer Sprachen bereitstellen, die mit diesem Objekt verknüpft werden. Zum Beispiel in C müssen Sie angeben .h Dateien, die zu Ihren Objektdateien gehören. Aber es ist trotzdem eine gute Übung.
In Sprachen mit textbasierten Includes wie C oder C++ müssen Sie, wenn Sie einen Funktionsprototyp ändern, ihn an zwei Stellen ändern. Einmal in der Header-Datei, einmal in der Implementierungsdatei.
Einige Linker können tatsächlich Inlining oder andere Optimierungen auf Assemblyebene durchführen.
– Phil Müller
12. März 2011 um 16:52 Uhr
Es gibt Compiler, die Objektdateien optimieren können. Neuere VC-Versionen tun das. Trotzdem gute Antwort, +1 von mir.
– sbi
12. März 2011 um 16:55 Uhr
+0 für die Nichterwähnung von Vorlagen in Nachteilen.
– Jakow Galka
12. März 2011 um 17:38 Uhr
@ybungalobill, Vorlagen? Im Fortran?!?
– SK-Logik
12. März 2011 um 18:55 Uhr
@Tomalak: Ehrlich gesagt weiß ich nicht, ob die (echte) Kompilierung bis zur Linkphase verschoben wird oder der Linker so schlau ist.
– sbi
12. März 2011 um 19:13 Uhr
Wenn Sie ein Projekt mit einigen 100 Quelldateien haben, möchten Sie es nicht neu kompilieren alle von ihnen jedes Mal, wenn man sich ändert. Indem Sie jede Quelldatei in eine separate Objektdatei kompilieren und nur die Quelldateien neu kompilieren, die von einer Änderung betroffen sind, verbringen Sie nur ein Minimum an Zeit von der Änderung des Quellcodes bis zur neuen ausführbaren Datei.
make ist das übliche Werkzeug, das verwendet wird, um solche Abhängigkeiten zu verfolgen und Ihre Binärdatei neu zu erstellen, wenn sich etwas ändert. Normalerweise richten Sie ein, wovon jede Quelldatei abhängt (diese Abhängigkeiten können normalerweise von Ihrem Compiler generiert werden – in einem geeigneten Format für make), und lassen Sie make die Details zum Erstellen einer aktuellen Binärdatei erledigen.
Die .o-Datei ist die Objektdatei. Es ist eine Zwischendarstellung des endgültigen Programms.
Insbesondere hat die .o-Datei normalerweise kompilierten Code, aber was sie nicht hat, sind Endadressen für all die verschiedenen Routinen oder Daten.
Eines der Dinge, die ein Programm benötigt, bevor es ausgeführt werden kann, ist etwas Ähnliches wie ein Speicherabbild.
Zum Beispiel.
Wenn Sie Ihr Hauptprogramm haben und es eine Routine A aufruft. (Das ist Faux Fortran, ich habe es seit Jahrzehnten nicht mehr berührt, also arbeiten Sie hier mit mir zusammen.)
PROGRAM MAIN
INTEGER X,Y
X = 10
Y = SQUARE(X)
WRITE(*,*) Y
END
Dann haben Sie die SQUARE-Funktion.
FUNCTION SQUARE(N)
SQUARE = N * N
END
Es handelt sich um individuell zusammengestellte Einheiten. Sie können sehen, dass beim Kompilieren von MAIN nicht bekannt ist, wo “SQUARE” ist und an welcher Adresse es sich befindet. Es muss wissen, dass, wenn es die Anweisung JUMP SUBROUTINE (JSR) des Mikroprozessors aufruft, die Anweisung irgendwo hingehen muss.
Die .o-Datei enthält bereits die JSR-Anweisung, aber sie hat nicht den tatsächlichen Wert. Das kommt später in der Verknüpfungs- oder Ladephase (abhängig von Ihrer Anwendung).
Die Datei MAINS .o enthält also den gesamten Code für main und eine Liste von Referenzen, die aufgelöst werden sollen (insbesondere SQUARE). SQUARE ist im Grunde eigenständig, es hat keine Referenzen, aber gleichzeitig hatte es noch keine Adresse, wo es im Speicher existiert.
Der Linker entfernt alle .o-Dateien und kombiniert sie zu einer einzigen EXE-Datei. Früher war kompilierter Code buchstäblich ein Erinnerungsbild. Das Programm startete an irgendeiner Adresse und wurde einfach en gros in den RAM geladen und dann ausgeführt. In dem Szenario können Sie also sehen, wie der Linker die beiden .o-Dateien nimmt und sie miteinander verkettet (um die tatsächliche Adresse von SQUAREs zu erhalten), dann würde er zurückgehen und die SQUARE-Referenz in MAIN finden und die Adresse eingeben.
Moderne Linker gehen nicht ganz so weit und verschieben einen Großteil dieser abschließenden Verarbeitung auf den Zeitpunkt, an dem das Programm tatsächlich geladen wird. Aber das Konzept ist ähnlich.
Durch Kompilieren in .o-Dateien erhalten Sie wiederverwendbare Logikeinheiten, die dann später durch die Verknüpfungs- und Ladeprozesse vor der Ausführung kombiniert werden.
Der andere nette Aspekt ist, dass die .o-Dateien aus verschiedenen Sprachen stammen können. Solange die Aufrufmechanismen kompatibel sind (dh wie Argumente an und von Funktionen und Prozeduren übergeben werden), wird die Quellsprache nach dem Kompilieren in ein .o weniger relevant. Sie können beispielsweise C-Code mit FORTRAN-Code verknüpfen, kombinieren.
In PHP et all ist der Prozess anders, da der gesamte Code zur Laufzeit in ein einzelnes Bild geladen wird. Sie können die FORTRANs .o-Dateien so betrachten, als würden Sie den Include-Mechanismus von PHP verwenden, um Dateien zu einem großen, zusammenhängenden Ganzen zusammenzufügen.
Sehr gut. Das hat mir einiges klar gemacht. Ich wünschte, ich hätte das früher gelesen.
– Noel Widmer
10. Oktober 2017 um 16:59 Uhr
Ich möchte anmerken, dass Sie Fortran C C++ und vielleicht sogar Ada oder Go auch in einem gcc-Kompilierungsbefehl kombinieren können. Ich bin mir nicht sicher, ob es vor 10 Jahren so war, aber die Funktion ist nicht sehr neu.
– Wladimir F. Героям слава
22. Juni 2021 um 19:10 Uhr
Ein weiterer Grund, abgesehen von der Kompilierungszeit, ist, dass der Kompilierungsprozess a mehrstufiger Prozess.
Die Objektdateien sind nur eine Zwischenausgabe dieses Prozesses. Sie werden schließlich vom Linker verwendet, um die ausführbare Datei zu erstellen.
Bo Persson
Wir kompilieren zu Objektdateien, um sie zu größeren ausführbaren Dateien zusammenfügen zu können. Das ist nicht der einzige Weg, es zu tun.
Es gibt auch Compiler, die das nicht so machen, sondern in den Speicher kompilieren und das Ergebnis sofort ausführen. Früher, als Studenten Mainframes verwenden mussten, war dies Standard. Turbo Pascal hat es auch so gemacht.
13893200cookie-checkWarum zuerst in eine Objektdatei kompilieren?yes
Im Allgemeinen verwenden wir obj-Dateien zum “Zwischenspeichern” der Kompilierung. Erleichtern Sie die Wiederverwendung von altem kompiliertem Code, um die Kompilierungszeit zu minimieren.
– Stefan
12. März 2011 um 16:44 Uhr
“Code” ist in diesem Zusammenhang ein nicht zählbares Substantiv; daher ist “zwei Codes” falsch.
– Leichtigkeitsrennen im Orbit
12. März 2011 um 17:28 Uhr
Die Verwendung von “Code” als Zählnomen für Programme und Bibliotheken ist eine leider übliche Verwendung unter Physikern. Es ist unwahrscheinlich, dass Korrekturen in dieser Gemeinschaft stattfinden.
– wnoise
13. März 2011 um 20:13 Uhr
@wnoise Aber wir werden es versuchen, verdammt noch mal. Wir werden es versuchen.
– AndyPerfekt
14. März 2011 um 19:10 Uhr
Ha, danke für die Korrektur. Ich hatte diese Programme nie “Codes” genannt, bis ich anfing, hier zu arbeiten.
– Tomshafer
14. März 2011 um 20:05 Uhr