Warum zuerst in eine Objektdatei kompilieren?

Lesezeit: 7 Minuten

Benutzeravatar von Tomshafer
tomschafer

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

Benutzeravatar von kriss
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.

Der mehrteilige Prozess.

Die Objektdateien sind nur eine Zwischenausgabe dieses Prozesses. Sie werden schließlich vom Linker verwendet, um die ausführbare Datei zu erstellen.

Benutzeravatar von Bo Persson
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.

1389320cookie-checkWarum zuerst in eine Objektdatei kompilieren?

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

Privacy policy