2009-02-04 8 views
6

Kann jemand erklären, wie Kompilierung funktioniert?Der Kompilierungsprozess

Ich kann nicht scheinen, um herauszufinden, wie Kompilierung funktioniert ..

Um genauer zu sein, hier ist ein Beispiel .. Ich versuche, einige Codes in MSVC++ 6 zu schreiben einen Lua Zustand zu laden ..

ich habe schon:

  • die zusätzlichen Verzeichnisse für die Bibliothek festgelegt und Include-Dateien auf die richtigen Verzeichnisse
  • verwendet extern „C“ (da Lua C nur ist oder so höre ich)
  • INCLUDE die richtigen Header-Dateien

Aber ich bin immer noch einige Fehler in MSVC++ 6 über ungelöste externe Symbole (für die Lua-Funktionen, die ich verwendet) zu bekommen.

So gerne ich wissen würde, wie ich dieses Problem lösen und weitermachen könnte, ich denke, es wäre viel besser für mich, wenn ich die zugrundeliegenden Prozesse verstehen würde, also könnte jemand vielleicht eine schöne Erklärung dafür schreiben Dies? Was ich suche, ist der Prozess zu wissen .. Es könnte wie folgt aussehen:

Schritt 1:

  • Input: Der Quellcode (e)
  • Prozess: Parsing (vielleicht mehr hinzufügen Detail hier hier ist, was Ausgang ..

Schritt 2::)

  • Ausgabe

    • Eingabe: Was auch immer aus Schritt 1 ausgegeben wurde, und was sonst noch benötigt wird (Bibliotheken? DLLs? .damit? .lib?)
    • Prozess: was auch immer mit dem Eingang
    • Ausgabe erfolgt: was auch immer Ausgang

    und so ..

    Dank ..

    Vielleicht erklärt dies ist auf dem, was Symbole sind, was genau "linking" ist, was "object" code oder was auch immer ist ..

    Danke .. Sorry für so ein noob ..

    P.S. Dies muss nicht sprachspezifisch sein. Aber fühlen Sie sich frei, es in der Sprache auszudrücken, in der Sie sich am wohlsten fühlen. :)

    EDIT: Also wie auch immer, ich konnte die Fehler beheben, Es stellt sich heraus, dass ich die .lib-Datei dem Projekt manuell hinzufügen muss; einfach das Bibliotheksverzeichnis anzugeben (wo sich die .lib befindet) in den IDE Einstellungen oder Projekteinstellungen funktioniert nicht.

    Allerdings haben mir die Antworten etwas geholfen, den Prozess besser zu verstehen. Vielen Dank! .. Wenn jemand noch eine gründliche Anleitung schreiben möchte, bitte ..:)

    EDIT: Nur für zusätzliche Referenz, fand ich zwei Artikel von einem Autor (Mike Diehl) ganz gut zu erklären .. :) Examining the Compilation Process: Part 1 Examining the Compilation Process: Part 2

  • +0

    http://steve-yegge.blogspot.com/2007/06/rich-programmer-food.html Ich fand das irgendwo, das erklärt es irgendwie .. – krebstar

    Antwort

    10

    Von der Quelle zur ausführbaren Datei ist in der Regel ein zweistufiger Prozess für C und zugehörige Sprachen, obwohl die IDE dies wahrscheinlich als einen einzigen Prozess darstellt.

    1/Sie codieren Ihre Quelle und führen sie durch den Compiler. Der Compiler benötigt zu diesem Zeitpunkt Ihre Quelle und die Header-Dateien der anderen Sachen, mit denen Sie verlinken werden (siehe unten).

    Kompilierung besteht darin, Ihre Quelldateien in Objektdateien umzuwandeln. Objektdateien haben Ihren kompilierten Code und genügend Informationen, um zu wissen, welche anderen Dinge sie benötigen, aber nicht wo finden Sie das andere Zeug (z. B. die LUA-Bibliotheken).

    2/Die nächste Stufe verbindet alle Ihre Objektdateien mit Bibliotheken, um eine ausführbare Datei zu erstellen. Ich werde hier die dynamische Verknüpfung nicht behandeln, da dies die Erklärung mit wenig Nutzen erschweren wird.

    Sie müssen nicht nur die Verzeichnisse angeben, in denen der Linker den anderen Code finden kann, sondern Sie müssen auch die eigentliche Bibliothek angeben, die diesen Code enthält. Die Tatsache, dass Sie nicht aufgelöste externe Daten erhalten, weist darauf hin, dass Sie dies nicht getan haben.

    Betrachten Sie als Beispiel den folgenden vereinfachten C-Code (xx.c) und Befehl.

    #include <bob.h> 
    int x = bob_fn(7); 
    
    cc -c -o xx.obj xx.c 
    

    Dies kompiliert die xx.c Datei zu xx.obj. Die bob.h enthält den Prototyp für bob_fn(), so dass die Kompilierung erfolgreich sein wird. Die -c weist den Compiler an, eine Objektdatei anstelle einer ausführbaren Datei zu generieren, und -o xx.obj legt den Namen der Ausgabedatei fest.

    Aber die tatsächlichen Code für bob_fn() nicht in der Header-Datei ist aber in /bob/libs/libbob.so, so Link, müssen Sie so etwas wie:

    cc -o xx.exe xx.obj -L/bob/libs;/usr/lib -lbob 
    

    Das schafft xx.exe von xx.obj, mit Bibliotheken (nach dem in die angegebenen Pfade) der Form libbob.so (die lib und .so werden normalerweise vom Linker hinzugefügt). In diesem Beispiel legt -L den Suchpfad für Bibliotheken fest. -l gibt eine Bibliothek an, die bei Bedarf in die ausführbare Datei aufgenommen werden soll. Der Linker nimmt normalerweise den "Bob" und findet die erste relevante Bibliotheksdatei in dem Suchpfad, der durch -L spezifiziert ist.

    Eine Bibliotheksdatei ist eigentlich eine Sammlung von Objektdateien (eine Art, wie eine Zip-Datei mehrere andere Dateien enthält, aber nicht unbedingt komprimiert) - wenn das erste relevante Vorkommen eines undefinierten externen Objekts gefunden wird, wird die Objektdatei kopiert die Bibliothek und hinzugefügt, um die ausführbare Datei wie Ihre xx.obj Datei. Dies wird im Allgemeinen so lange fortgesetzt, bis keine unaufgelösten Externalitäten mehr vorhanden sind. Die "relevante" Bibliothek ist eine Modifikation des "bob" -Text, sie kann nach libbob.a, libbob.dll, libbob.so, bob.a, bob.dll, bob.so und so weiter suchen. Die Relevanz wird vom Linker selbst entschieden und sollte dokumentiert werden.

    Wie es funktioniert hängt vom Linker ab, aber das ist es im Grunde genommen.

    1/Alle Ihre Objektdateien enthalten eine Liste von nicht aufgelösten externen Elementen, die aufgelöst werden müssen. Der Linker stellt all diese Objekte zusammen und stellt die Verbindungen zwischen ihnen her (löst so viele externe wie möglich auf).

    2/Dann, für jede externe immer noch ungelöst, kämmt der Linker die Bibliothek Dateien auf der Suche nach einer Objektdatei, die die Verbindung erfüllen kann. Wenn es gefunden wird, zieht es es ein - dies kann zu weiteren unaufgelösten Äußerlichkeiten führen, da das eingezogene Objekt eine eigene Liste von externen Elementen haben kann, die erfüllt werden müssen.

    3/Wiederholen Sie Schritt 2, bis keine unaufgelösten externen Daten mehr vorhanden sind oder keine Möglichkeit besteht, sie aus der Bibliotheksliste aufzulösen (hier war Ihre Entwicklung, da Sie die LUA-Bibliotheksdatei nicht eingefügt haben).

    Die Komplikation, die ich bereits erwähnte, ist dynamische Verknüpfung. Das ist, wo Sie mit einem Stub einer Routine (Art eines Markers) verknüpfen, anstatt der eigentlichen Routine, die später bei Ladezeit aufgelöst wird (wenn Sie die ausführbare Datei ausführen). Dinge wie die allgemeinen Windows-Steuerelemente befinden sich in diesen DLLs, so dass sie sich ändern können, ohne die Objekte in eine neue ausführbare Datei neu verknüpfen zu müssen.

    +0

    Wow das ist gut .. Ich akzeptiere dies als die Antwort .. :) BTW, können Sie ein bisschen mehr über die Syntax erklären, die Sie verwendeten? Wofür steht -lbob im zweiten Befehl? – krebstar

    +0

    Fertig, obwohl die erwähnten Befehle UNIX-Befehle sind. In der MSVC-IDE ist dies anders, wo Sie Bibliothekspfade und Bibliotheksnamen in den Projektkonfigurationsdialogen festlegen. – paxdiablo

    +0

    Kein Problem Pax, Sie waren ziemlich hilfreich :) Eine letzte Sache .. Also in einer MSVC-Umgebung, .LIB-Dateien sind statische Bibliotheken, die im Projekt enthalten sein müssen, und DLL-Dateien sind dynamische Bibliotheken, die über eine geladen werden LoadLibrary-Befehl oder ähnliches? Ist das der einzige Unterschied zwischen den beiden? – krebstar

    1

    Sie haben in Projekteinstellung gehen und fügen Sie ein Verzeichnis hinzu, in dem Sie diese LUA-Bibliothek * .lib-Dateien irgendwo auf der Registerkarte "Linker" haben. Einstellung namens "including libraries" oder so, sorry, ich kann nicht nachsehen.

    Der Grund, warum Sie "nicht aufgelöste externe Symbole" erhalten, liegt daran, dass die Kompilierung in C++ in zwei Phasen abläuft. Zuerst wird der Code kompiliert, jede CPP-Datei in ihrer eigenen OBJ-Datei, dann startet "Linker" und fügt alle OBJ-Dateien in die EXE-Datei ein. Die .lib-Datei ist nur ein paar OBJ-Dateien, die zusammengefügt wurden, um die Verteilung von Bibliotheken ein wenig einfacher zu machen. Also, indem Sie alle "#include" und extern-Deklaration hinzugefügt haben, sagten Sie dem Compiler, dass es irgendwo möglich wäre, Code mit diesen Signaturen zu finden, aber Linker kann diesen Code nicht finden, weil er nicht weiß, wo diese .lib-Dateien tatsächlich sind Code wird platziert.

    Stellen Sie sicher, dass Sie REDME der Bibliothek gelesen haben, normalerweise haben sie ziemlich detaillierte Erklärungen, was Sie tun mussten, um es in Ihren Code aufzunehmen.

    +0

    Ich habe das versucht, aber es hat nicht funktioniert . Ich werde die Readme-Datei erneut durchsuchen. – krebstar

    +0

    Das Verzeichnis ist nicht genug - Sie müssen auch die Bibliotheksdatei angeben. – paxdiablo

    5

    Schritt 1 - Compiler:

    • Input: Quellcode-Datei [s]
    • Prozess: Quellcode-Parsing und das Übersetzen in Maschinencode
    • Output: Objektdatei [s], die aus [ s]:
      • Die Namen von Symbolen, die in diesem Objekt definiert sind, und der diese Objektdatei „exportiert“
      • der Code Maschine mit ea zugeordnet ch Symbol, das in dieser Objektdatei definiert ist
      • Die Namen von Symbolen, die nicht in dieser Objektdatei definiert sind, von denen jedoch die Software in dieser Objektdatei abhängt und zu der sie später verknüpft werden muss, dh Namen, die diese Objektdatei " Import“

    Schritt 2 - Linking:

    • Input:
      • Objektdatei [s] aus Schritt 1
      • Bibliotheken anderer Objekte (z.B.von dem O/S und andere Software)
    • Prozess:
      • Für jedes Objekt, das Sie
      • Erhalten Sie die Liste von Symbolen, die dieses Objekt Importe
      • Finden Sie diese Symbole in anderen verknüpfen möchten Bibliotheken
      • Link zu den entsprechenden Bibliotheken auf Ihre Objektdateien
    • Ausgang: eine einzelne, ausführbare Datei, Dazu gehören der Maschinencode aus allen Ihren Objekten sowie die Objekte aus Bibliotheken, die mit Ihren Objekten importiert (verknüpft) wurden.
    +0

    ChrisW, weißt du, wie genau der Linker die Symbole in den anderen Bibliotheken findet? Durchsucht es nur eine angegebene lib-Datei oder kann es ein Verzeichnis durchsuchen und alle lib-Dateien versuchen? Danke .. – krebstar

    +0

    Sie geben eine explizite Liste von lib-Dateinamen (und eine Liste von Verzeichnissen, in denen diese spezifischen lib-Dateien gefunden werden können): so müssen Sie die Namen der lib-Dateien angeben, die die Symbole enthalten, auf denen Deine Quelle hängt davon ab. – ChrisW

    +0

    Google fand für mich ein Beispielprogramm, das Lua verwendet: http://www.codeproject.com/KB/library/lua.aspx ... laut diesem Beispiel ist der Dateiname der Lua-Bibliotheksdatei "lua.lib" . – ChrisW

    3

    Die beiden Hauptschritte sind Kompilierung und Verknüpfung.

    Die Kompilierung benötigt einzelne Kompilierungseinheiten (das sind einfache Quelldateien mit allen darin enthaltenen Überschriften) und erstellt Objektdateien. Jetzt, in diesen Objektdateien, gibt es viele Funktionen (und andere Dinge, wie statische Daten), die an bestimmten Orten (Adressen) definiert sind. Im nächsten Schritt, dem Verknüpfen, werden noch ein paar zusätzliche Informationen über diese Funktionen benötigt: ihre Namen. So werden diese auch gespeichert. Eine einzelne Objektdatei kann auf Funktionen verweisen (weil sie sie aufrufen möchte, wenn Code ausgeführt wird), die sich tatsächlich in anderen Objektdateien befinden, aber da es sich hier um eine einzelne Objektdatei handelt, nur symbolische Referenzen (deren 'Namen') Diese anderen Funktionen sind in der Objektdatei gespeichert.

    Als nächstes kommt die Verknüpfung (beschränken wir uns hier auf statische Verknüpfung). Die Verknüpfung besteht darin, dass die Objektdateien, die im ersten Schritt erstellt wurden (entweder direkt oder nachdem sie in eine .lib-Datei zusammengefasst wurden) zusammengenommen werden und eine ausführbare Datei erstellt wird. Im Verknüpfungsschritt werden all diese symbolischen Referenzen von einer Objektdatei oder einer Bibliothek zu einer anderen aufgelöst (falls dies möglich ist), indem die Namen im richtigen Objekt nachgeschlagen, die Adresse der Funktion gefunden und die Adressen in die richtiger Ort.

    , nun etwas über die ‚extern‚C‘‘, was Sie brauchen, zu erklären:

    C nicht Funktion Überlastung hat. Eine Funktion ist immer an ihrem Namen erkennbar. Wenn Sie Code als C-Code kompilieren, wird daher nur der echte Name der Funktion in der Objektdatei gespeichert.

    C++ hat jedoch etwas namens "Funktion/Methode überladen". Dies bedeutet, dass der Name einer Funktion nicht mehr ausreicht, um sie zu identifizieren. C++ - Compiler erstellen daher 'Namen' für Funktionen, die die Prototypen der Funktion enthalten (da der Name und der Prototyp eine Funktion eindeutig identifizieren). Dies ist bekannt als "Name Mangling".

    Die 'extern' C '' - Spezifikation wird benötigt, wenn Sie eine Bibliothek verwenden möchten, die als C-Code (z. B. die vorkompilierten Lua-Binärdateien) aus einem C++ - Projekt kompiliert wurde.

    Für Ihr genaues Problem: Wenn es immer noch nicht funktioniert, können diese Hinweise helfen: * Haben die Lua Binaries mit der gleichen Version von VC++ kompiliert worden? * Können Sie Lua selbst kompilieren, entweder in Ihrer VC-Lösung oder als separates Projekt als C++ - Code? * Sind Sie sicher, dass Sie alle "externen" C-Dinge korrekt haben?