Dies ist der Befehl makepp_tutorial_compilation, der beim kostenlosen Hosting-Anbieter OnWorks mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, dem Windows-Online-Emulator oder dem MAC OS-Online-Emulator ausgeführt werden kann
PROGRAMM:
NAME/FUNKTION
makepp_tutorial_compilation – Unix-Kompilierungsbefehle
BESCHREIBUNG
Überspringen Sie diese Handbuchseite, wenn Sie gut wissen, was die Kompilierungsbefehle bewirken.
Ich finde, dass beunruhigend wenige Leute in ihren Programmierkursen darüber unterrichtet werden, wie das geht
um Programme zu kompilieren, nachdem sie sie geschrieben haben. Anfänger verlassen sich entweder auf eine einzelne
gespeicherten Befehl oder auf den eingebauten Regeln in make. Ich war überrascht
extrem computerkundige Leute, die gelernt haben, ohne Optimierung zu kompilieren, weil
Ihnen wurde einfach nie gesagt, wie wichtig es ist. Rudimentäre Kenntnisse darüber, wie Kompilierung funktioniert
Die Arbeit mit Befehlen kann dazu führen, dass Ihre Programme doppelt so schnell oder schneller ausgeführt werden, es lohnt sich also zumindest
fünf Minuten. Auf dieser Seite wird nahezu alles beschrieben, was Sie zum Kompilieren von C wissen müssen
oder C++-Programme auf nahezu jeder Unix-Variante.
Die Beispiele beziehen sich hauptsächlich auf C, da die C++-Kompilierung bis auf den Namen identisch ist
des Compilers ist unterschiedlich. Angenommen, Sie kompilieren Quellcode in einer Datei namens
„xyz.c“ und Sie möchten ein Programm namens „xyz“ erstellen. Was muss passieren?
Sie wissen vielleicht, dass Sie Ihr Programm in einem Schritt erstellen können, indem Sie einen Befehl wie diesen verwenden:
cc -g xyz.c -o xyz
Dies wird funktionieren, verbirgt jedoch einen zweistufigen Prozess, den Sie verstehen müssen, wenn Sie dies tun
Makefiles schreiben. (Eigentlich sind es mehr als zwei Schritte, aber Sie müssen nur
(Sie müssen zwei davon verstehen.) Bei einem Programm mit mehr als einem Modul sind dies normalerweise zwei Schritte
explizit getrennt.
Zusammenstellung
Der erste Schritt ist die Übersetzung Ihres C- oder C++-Quellcodes in eine Binärdatei namens
eine Objektdatei. Objektdateien haben normalerweise die Erweiterung „.o“. (Für einige neuere
In Projekten wird „.lo“ auch für eine etwas andere Art von Objektdatei verwendet.)
Der Befehl zum Erstellen einer Objektdatei unter Unix sieht in etwa so aus:
cc -g -c xyz.c -o xyz.o
„cc“ ist der C-Compiler. Manchmal werden alternative C-Compiler verwendet; eine sehr häufige ist
mit dem Namen „gcc“. Ein gängiger C++-Compiler ist der GNU-Compiler, üblicherweise „g++“ genannt. Virtuell
Alle C- und C++-Compiler unter Unix haben für den Rest des Befehls die gleiche Syntax (zumindest
für Grundoperationen), der einzige Unterschied wäre also das erste Wort.
Was die Option „-g“ bewirkt, erklären wir später.
Die Option „-c“ weist den C-Compiler an, eine „.o“-Datei als Ausgabe zu erzeugen. (Wenn nicht
Geben Sie „-c“ an, dann wird der zweite Kompilierungsschritt automatisch ausgeführt.)
Die Option „-o xyz.o“ teilt dem Compiler mit, wie die Objektdatei heißt. Du kannst
Lassen Sie dies weg, solange der Name der Objektdatei mit dem Namen der Quelle übereinstimmt
Datei mit Ausnahme der Erweiterung „.o“.
Die Reihenfolge der Optionen und der Dateinamen spielt größtenteils keine Rolle. Eins
Eine wichtige Ausnahme besteht darin, dass die Ausgabedatei unmittelbar nach „-o“ folgen muss.
Linking
Der zweite Schritt beim Erstellen eines Programms wird aufgerufen Linking. Eine Objektdatei kann nicht ausgeführt werden
direkt; Es ist eine Zwischenform, die sein muss verknüpft zu anderen Komponenten, um
ein Programm erstellen. Weitere Komponenten könnten sein:
· Bibliotheken. A BibliothekGrob gesagt handelt es sich um eine Sammlung von Objektmodulen
bei Bedarf enthalten. Wenn Ihr Programm beispielsweise die Funktion „printf“ aufruft, dann
Die Definition der Funktion „printf“ muss aus der System-C-Bibliothek eingebunden werden.
Einige Bibliotheken werden automatisch in Ihr Programm eingebunden (z. B. die mit
„printf“), sodass Sie sich keine Sorgen darüber machen müssen.
· Von anderen Quelldateien in Ihrem Programm abgeleitete Objektdateien. Wenn Sie Ihre schreiben
Wenn Sie das Programm so anpassen, dass es tatsächlich über mehrere Quelldateien verfügt, kompilieren Sie normalerweise jede davon
Quelldatei in eine separate Objektdatei umwandeln und diese dann alle miteinander verknüpfen.
Die Linker ist das Programm, das für die Erfassung einer Sammlung von Objektdateien und verantwortlich ist
Bibliotheken und verknüpfen sie, um eine ausführbare Datei zu erstellen. Die ausführbare Datei ist
das Programm, das Sie tatsächlich ausführen.
Der Befehl zum Verknüpfen des Programms sieht in etwa so aus:
cc -g xyz.o -o xyz
Es mag seltsam erscheinen, aber wir führen normalerweise dasselbe Programm („cc“) aus, um die Verknüpfung durchzuführen. Was
Unter der Oberfläche passiert, dass das Programm „cc“ die Kontrolle sofort an a übergibt
anderes Programm (der Linker, manchmal auch Loader oder „ld“ genannt) nach dem Hinzufügen einer Nummer
komplexer Informationen an die Befehlszeile. Beispielsweise teilt „cc“ „ld“ mit, wo
Die Systembibliothek umfasst die Definition von Funktionen wie „printf“. Bis du
Wenn Sie mit dem Schreiben gemeinsam genutzter Bibliotheken beginnen, müssen Sie sich normalerweise nicht direkt mit „ld“ befassen.
Wenn Sie „-o xyz“ nicht angeben, heißt die Ausgabedatei scheinbar „a.out“.
für mich eine völlig nutzlose und verwirrende Konvention. Geben Sie also immer „-o“ an
Verknüpfungsschritt.
Wenn Ihr Programm über mehr als eine Objektdatei verfügt, sollten Sie alle Objektdateien angeben
den Link-Befehl.
Warum Sie technische zu getrennte die Schritte
Warum verwenden Sie nicht einfach den einfachen, einstufigen Befehl wie diesen:
cc -g xyz.c -o xyz
anstelle der komplizierteren zweistufigen Kompilierung
cc -g -c xyz.c -o xyz.o
cc -g xyz.o -o xyz
wenn intern das erste in das zweite umgewandelt wird? Der Unterschied ist nur wichtig, wenn
Es gibt mehr als ein Modul in Ihrem Programm. Angenommen, wir haben ein zusätzliches Modul,
„abc.c“. Nun sieht unsere Zusammenstellung so aus:
# Einstufiger Befehl.
cc -g xyz.c abc.c -o xyz
or
# Zweistufiger Befehl.
cc -g -c xyz.c -o xyz.o
cc -g -c abc.c -o abc.o
cc -g xyz.o abc.o -o xyz
Die erste Methode wird natürlich intern in die zweite Methode umgewandelt. Das heisst
dass sowohl „xyz.c“ als auch „abc.c“ bei jeder Ausführung des Befehls neu kompiliert werden. Aber wenn du
nur „xyz.c“ geändert, es besteht keine Notwendigkeit, „abc.c“ neu zu kompilieren, daher ist die zweite Zeile der beiden
Bühnenbefehle müssen nicht ausgeführt werden. Dies kann einen großen Unterschied bei der Zusammenstellung machen
Zeit, insbesondere wenn Sie viele Module haben. Aus diesem Grund bleiben praktisch alle Makefiles erhalten
Die beiden Kompilierungsschritte trennen sich.
Das sind so ziemlich die Grundlagen, aber es gibt noch ein paar weitere kleine Details, die Sie unbedingt beachten sollten
wissen über.
Fehlerbeseitigung vs Duplikatsentfernung, Harmonisierung und Optimierung auf Artikelebene
Normalerweise kompilieren Programmierer ein Programm entweder zum Debuggen oder aus Geschwindigkeitsgründen. Zusammenstellung
denn Geschwindigkeit heißt Duplikatsentfernung, Harmonisierung und Optimierung auf Artikelebene; Das Kompilieren mit Optimierung kann dazu führen, dass Ihr Code bis zu XNUMX m lang läuft
5-mal schneller oder mehr, abhängig von Ihrem Code, Ihrem Prozessor und Ihrem Compiler.
Warum sollten Sie angesichts solch dramatischer Gewinne überhaupt nicht optimieren wollen? Am meisten
Eine wichtige Antwort ist, dass die Optimierung den Einsatz eines Debuggers deutlich erschwert
(manchmal unmöglich). (Wenn Sie nichts über einen Debugger wissen, ist es Zeit, es zu lernen.
Die halbe Stunde oder Stunde, die Sie damit verbringen, die Grundlagen zu erlernen, wird sich um ein Vielfaches auszahlen
in der Zeit, die Sie später beim Debuggen sparen. Ich würde empfehlen, mit einem GUI-Debugger zu beginnen
wie „kdbg“, „ddd“ oder „gdb“ werden in Emacs ausgeführt (siehe die Infoseiten zu gdb für).
(Anweisungen dazu).) Optimierung ordnet Anweisungen neu an und kombiniert sie, entfernt sie
unnötige temporäre Variablen und ordnet Ihren Code im Allgemeinen so um, dass er sehr übersichtlich ist
Es ist schwierig, in einem Debugger zu folgen. Das übliche Verfahren besteht darin, Ihren Code zu schreiben und zu kompilieren
ohne Optimierung, debuggen Sie es und aktivieren Sie dann die Optimierung.
Damit der Debugger funktioniert, muss der Compiler nicht nur kooperieren, sondern auch nicht
Optimierung, sondern auch durch das Einfügen von Informationen über die Namen der Symbole in das Objekt
Datei, damit der Debugger weiß, wie die Dinge heißen. Dies ist die Kompilierung „-g“.
Option tut.
Wenn Sie mit dem Debuggen fertig sind und Ihren Code optimieren möchten, ersetzen Sie einfach „-g“ durch
"-Ö". Bei vielen Compilern können Sie durch Anhängen steigende Optimierungsgrade angeben
eine Zahl nach „-O“. Möglicherweise können Sie auch andere Optionen angeben, die die Leistung erhöhen
Geschwindigkeit unter bestimmten Umständen (möglicherweise als Kompromiss bei erhöhter Speichernutzung). Sehen
Weitere Informationen finden Sie in der Manpage Ihres Compilers. Hier ist zum Beispiel ein optimierender Kompilierungsbefehl
das ich häufig mit dem „gcc“-Compiler verwende:
gcc -O6 -malign-double -c xyz.c -o xyz.o
Möglicherweise müssen Sie mit verschiedenen Optimierungsoptionen experimentieren, um das absolut Beste zu erzielen
Leistung. Möglicherweise benötigen Sie unterschiedliche Optionen für verschiedene Codeteile. Allgemein
Ein einfaches Optimierungsflag wie „-O6“ funktioniert bei vielen Compilern und in der Regel
liefert ziemlich gute Ergebnisse.
Warnung: In seltenen Fällen macht Ihr Programm nicht genau das Gleiche
es wird mit Optimierung kompiliert. Dies kann auf (1) eine von Ihnen getroffene ungültige Annahme zurückzuführen sein
in Ihrem Code war das ohne Optimierung harmlos, verursacht aber Probleme, weil das
Der Compiler nimmt sich die Freiheit, Dinge bei der Optimierung neu anzuordnen. oder (2) leider,
Compiler haben auch Fehler, einschließlich Fehler in ihren Optimierern. Für einen stabilen Compiler wie
"gcc" auf einer gängigen Plattform wie einem Pentium sind Optimierungsfehler selten ein Problem (Stand:
im Jahr 2000 - vor ein paar Jahren gab es Probleme).
Wenn Sie in Ihrem Kompilierungsbefehl weder „-g“ noch „-O“ angeben, wird das resultierende Objekt
Die Datei eignet sich weder zum Debuggen noch zum schnellen Ausführen. Aus irgendeinem Grund ist dies der Fall
Standard. Geben Sie also immer entweder „-g“ oder „-O“ an.
Auf einigen Systemen müssen Sie „-g“ sowohl beim Kompilieren als auch beim Verknüpfen angeben; auf andere
(z. B. Linux) muss es nur beim Kompilierungsschritt angegeben werden. Auf einigen Systemen ist „-O“
bewirkt in der Verknüpfungsphase tatsächlich etwas anderes, während es bei anderen keine Auswirkung hat.
In jedem Fall ist es immer unbedenklich, für beide Befehle „-g“ oder „-O“ anzugeben.
Warnungen
Die meisten Compiler sind in der Lage, eine Reihe häufiger Programmierfehler zu erkennen (z. B.
vergessen, einen Wert von einer Funktion zurückzugeben, die einen Wert zurückgeben soll). Normalerweise,
Sie möchten Warnungen aktivieren. Wie Sie dies tun, hängt von Ihrem Compiler ab (siehe den Mann
Seite), aber mit dem „gcc“-Compiler verwende ich normalerweise so etwas:
gcc -g -Wall -c xyz.c -o xyz.o
(Manchmal füge ich aufgrund einer Warnung auch „-Wno-uninitialized“ nach „-Wall“ hinzu
normalerweise falsch, das beim Optimieren auftaucht.)
Diese Warnungen haben mir viele Stunden beim Debuggen erspart.
Andere nützlich Zusammenstellung Optionen
Oftmals werden notwendige Include-Dateien in einem anderen Verzeichnis als dem aktuellen gespeichert
Verzeichnis oder das System-Include-Verzeichnis (/ usr / include). Dies passiert häufig, wenn
Sie verwenden eine Bibliothek, die Include-Dateien enthält, um die Funktionen oder Klassen zu definieren.
Angenommen, Sie schreiben beispielsweise eine Anwendung, die die Qt-Bibliotheken verwendet. Du hast
Installierte eine lokale Kopie der Qt-Bibliothek in /home/users/joe/qt, Was bedeutet, dass die
Include-Dateien werden im Verzeichnis gespeichert /home/users/joe/qt/include. In Ihrem Code, Sie
möchte in der Lage sein, Dinge wie diese zu tun:
#enthalten
statt
#include „/home/users/joe/qt/include/qwidget.h“
Sie können den Compiler anweisen, in einem anderen Verzeichnis nach Include-Dateien zu suchen, indem Sie Folgendes verwenden
Kompilierungsoption „-I“:
g++ -I/home/users/joe/qt/include -g -c mywidget.cpp -o mywidget.o
Zwischen dem „-I“ und dem Verzeichnisnamen steht normalerweise kein Leerzeichen.
Wenn der C++-Compiler nach der Datei sucht qwidget.h, es wird reinschauen
/home/users/joe/qt/include bevor Sie im System-Include-Verzeichnis nachsehen. Du kannst
Geben Sie so viele „-I“-Optionen an, wie Sie möchten.
Die richtigen Bibliotheken
Wenn Sie möchten, müssen Sie den Linker häufig anweisen, eine Verknüpfung mit bestimmten externen Bibliotheken herzustellen
rufen alle Funktionen auf, die nicht Teil der Standard-C-Bibliothek sind. Das „-l“ (Kleinbuchstabe
L) Option besagt, dass mit einer bestimmten Bibliothek verknüpft werden soll:
cc -g xyz.o -o xyz -lm
„-lm“ besagt, dass eine Verknüpfung mit der Mathematikbibliothek des Systems hergestellt werden soll, die Sie bei Verwendung benötigen
Funktionen wie „sqrt“.
In acht nehmen: Wenn Sie mehr als eine „-l“-Option angeben, kann die Reihenfolge bei einigen einen Unterschied machen
Systeme. Wenn Sie undefinierte Variablen erhalten, obwohl Sie wissen, dass Sie diese eingefügt haben
Bibliothek, die sie definiert, können Sie versuchen, diese Bibliothek an das Ende des Befehls zu verschieben
oder sogar ein zweites Mal am Ende der Befehlszeile einfügen.
Manchmal sind die von Ihnen benötigten Bibliotheken nicht am Standardspeicherort des Systems gespeichert
Bibliotheken. „-labc“ sucht nach einer Datei namens libabc.a or libabc.so or libabc.sa in England,
Systembibliotheksverzeichnisse (/ Usr / lib und normalerweise auch ein paar andere Orte, je nachdem, was passiert
Art von Unix, das Sie verwenden). Die Option „-L“ gibt ein zusätzliches Verzeichnis zum Durchsuchen an
für Bibliotheken. Um das obige Beispiel noch einmal zu verwenden, nehmen wir an, Sie hätten die Qt-Bibliotheken installiert
in /home/users/joe/qt, was bedeutet, dass die Bibliotheksdateien vorhanden sind /home/users/joe/qt/lib.
Ihr Linkschritt für Ihr Programm könnte etwa so aussehen:
g++ -g test_mywidget.o mywidget.o -o test_mywidget -L/home/users/joe/qt/lib -lqt
(Auf einigen Systemen müssen Sie beim Verknüpfen in Qt auch andere Bibliotheken hinzufügen (z. B.
„-L/usr/X11R6/lib -lX11 -lXext“). Was Sie tun müssen, hängt von Ihrem System ab.)
Beachten Sie, dass zwischen „-L“ und dem Verzeichnisnamen kein Leerzeichen steht. Normalerweise die Option „-L“.
steht vor allen „-l“-Optionen, die es beeinflussen soll.
Woher wissen Sie, welche Bibliotheken Sie benötigen? Im Allgemeinen ist dies eine schwierige Frage und variiert
abhängig davon, welche Art von Unix Sie verwenden. Die Dokumentation zu den Funktionen bzw
In den von Ihnen verwendeten Klassen sollte angegeben werden, mit welchen Bibliotheken Sie eine Verknüpfung herstellen müssen. Wenn Sie verwenden
Für Funktionen oder Klassen aus einem externen Paket gibt es normalerweise eine Bibliothek, die Sie verknüpfen müssen
mit; Bei der Bibliothek handelt es sich normalerweise um eine Datei mit dem Namen „libabc.a“, „libabc.so“ oder „libabc.sa“.
wenn Sie eine „-labc“-Option hinzufügen müssen.
Manche Andere verwirrend
Sie haben vielleicht bemerkt, dass es möglich ist, Optionen anzugeben, die normalerweise gelten
Kompilierung im Verknüpfungsschritt und Optionen, die normalerweise für die Verknüpfung im gelten
Kompilierungsschritt. Folgende Befehle sind beispielsweise gültig:
cc -g -L/usr/X11R6/lib -c xyz.c -o xyz.o
cc -g -I/somewhere/include xyz.o -o xyz
Die irrelevanten Optionen werden ignoriert; Die obigen Befehle entsprechen genau diesem:
cc -g -c xyz.c -o xyz.o
cc -g xyz.o -o xyz
Verwenden Sie makepp_tutorial_compilation online über die Dienste von onworks.net
