JGU Logo JGU Logo JGU Logo JGU Logo

Institut für Informatik

Michael WAND
Christian ALI MEHMETI-GÖPEL
Sommersemester 2021DIGITAL

Einführung in die Softwareentwicklung

Letzte Änderung : 20:33 Uhr, 08 April 2021










Praktisches Arbeiten mit C++

Die Programmiersprache C++ hat eine recht lange Historie auf dem Buckel – wenn man den Vorgänger C mitzählt, sind es inzwischen fast 50 Jahre (oder 35, wenn man 1985 mit dem ersten Release von C++ startet). Die Sprache wird auf einer Vielfalt von Plattformen und Betriebssystemen eingesetzt, entsprechend heterogen sind die vielen verschiedenen Systemumgebungen, in denen man die Sprache benutzt.


In der Praxis hat das dazu geführt, dass die Einbindung der Sprache in das System relativ lose, anhand von Konventionen und kolportiertem Wissen erfolgt. Das macht die Benutzung schwieriger ohne das es dafür einen zwingenden technischen Grund gäbe. In diesem Dokument möchten wir etwas beim Einstieg helfen, indem wir anhand von ein paar Beispielen zeigen, wie man "den Compiler zum laufen" bekommt. Außerdem diskutieren wir noch einige Coding-Styles, deren Kern für unsere Übungen verpflichtend ist.

Wie bekomme ich meinen Compiler zu laufen?

Um mit C++ Arbeiten zu müssen braucht man mindestens:



Die Entwicklung mit diesen Tools ist möglich, aber sehr rustikal (um nicht zu sagen masochistisch). Optional würde man daher folgende Dinge hinzufügen:



Letzteres (die IDE) kommt oft in einem großen Paket, so dass man sich weniger Sorgen um die Details machen muss.


Wir schauen uns die Struktur und die Installation der C++-"Toolchain" nun genauer an. Um besser zu verstehen, wie alles zusammenspielt, fangen wir mit der "rustikalen" Kommandozeilenlösung an. Dies ist kein Masochismus – in der C++-Welt bauen so ziemlich alle Lösungen auf den Kommandozeilenwerkzeugen auf.


Auch eine moderne IDE wie Qt-Creator, Visual Studio oder CLion ruft im Hintergrund die ollen Kommandozeilenwerkzeuge auf, und interpretiert deren Text-Output um dem Benutzer Feedback zu geben. (Modernere Konzepte wie Roslyn in der C#-Welt sind in der traditionellen C++-Welt nocht nicht angekommen.)


Ok – genug gejammert – los geht's.


Installation eines C++-Compilers

Als erstes müssen wir den C++-Compiler installieren:


Linux

Installation unter Linux (am Beispiel Ubuntu) bzw. in einer virtuellen Maschine: Das folgende Video zeigt Schritt-für-Schritt, wie man die Compiler GCC/G++ und CLANG/CLANG++ unter Linux (Ubuntu-20) installiert. Mit Hilfe einer virtuellen Machine, wie VirtualBox, ist dies auch unter Windows oder MacOS problemlos nachzuvollziehen (sofern man einen Rechner besitzt, der hinreichend stark ist, was heißt, es sind insgesamt mindestens ca. 4GB Speicher verfügbar).


Aufgrund des eingebauten Packetmanagers in den meisten Linux Distributionen (in unserem Videobeispiel ist dies Ubuntu) gestaltet sich die Installation und die Konfiguration des Compilers trivial.


Installation der Compiler unter Linux (6min)
P01-Installation.webm (1920x1080),
P01-Installation-small.webm (853x480)
Man findet das Video auch auf Panopto.


tl;dwsudo apt-get install build-essential. Das war's.


Auch die Installation einer komplexeren IDE ist sehr einfach. Das nächste Video zeigt, wie wir den Qt-Creator unter Ubuntu installieren können, und dann damit interaktiv Programabläufe verfolgen können (mit dem integrierten "Debugger").


Installation von QTCreator und Debugging unter Linux (10min)
P02-IDE.webm (1920x1080),
P02-IDE-small.webm (853x480)
Man findet das Video auch auf Panopto.


tl;dwsudo apt-get install qt5-default qtcreator. Auch net schwer.

Microsoft Windows

Auch die Benutzung von MS Windows (oder MacOS) nativ (ohne VM) ist kein wesentliches problem Problem. Unter Windows ist es wahrscheinlich am einfachsten, den Compiler der Firma Microsoft (der C++-Compiler von Visual C++/Visual Studio) zu installieren. Dieser ist einzeln wie auch im Paket mit Visual Studio erhältlich (für das Lösen von Übungsaufgaben sollten auch keine Lizenzkosten anfallen; für definitive Aussage lesen Sie aber bitte genau die Bedingungen der Firma Microsoft durch). Nach der Installation ist der Compiler nicht so stark im Betriebssystem eingebunden wie unter (Ubuntu-) Linux; man muss noch per Hand einige Konfiguration durchführen. Um dies nicht manuell machen zu müssen, gibt es eine vorkonfigurierte Command-Shell, die man aus dem Startmenü und/oder mit einer entsprechenden Batch-Datei aufrufen kann. Danach stimmen alle Pfade und man kann wie unter Linux mit dem Compiler arbeiten. Die Details sind sehr genau in dem folgenden Dokument der Firma Microsoft erklärt: Verwenden des Microsoft C++-Toolsets über die Befehlszeile.


Für den GCC/G++ Compiler gibt es verschiedene Portierungen auf Windows – hier empfiehlt sich z.B. die Version des MinGW-Projektes. Bei der Konfiguration von Pfaden ist allerdings etwas Handarbeit nötig (die Grundprinzipien werden weiter unten erklärt).


Es gibt natürlich auch unter MS Windows die Option, die IDE QtCreator zu installieren. Informationen dazu finden Sie auf der Webseite des Herstellers www.qt.io. Dabei ist zu beachten, dass es von Qt eine kommerzielle wie auch eine OpenSource-Version gibt. Für die Lehrveranstaltung ist natürlich letzteres zu empfehlen (kommerzielle Lizenzen sind kostenintensiv).


Die Installationsroutine bietet des QtCreators für Windows bietet die Möglichkeit an, den MinGW-GCC/G++ Compiler direkt mitzuinstallieren. Innerhalb der IDE werden auch alle Pfade automatisch konfiguriert, so dass hier wenig Handarbeit nötig sein sollte. Bei der Benutzung auf der Kommandozeile muß man allerdings etwas nacharbeiten.


Die Qt-IDE erkennt auch automatisch eine Installation des Microsoft-Visual-C++-Compilers und kann diesen direkt aufrufen. Um hier den Debugger nutzen zu können, ist allerdings wieder etwas zusätzliche Arbeit nötig (man muss den Debugger für MSVC per Hand nachinstallieren); bei gcc ist er dabei.


tl;dr – Wenn Sie genug Speicher haben und wenig Erfahrung, probieren Sie Ubuntu in einer VM (ggf. auch WSL unter Windows 10); dass ist am einfachsten. Für natives Windows ist sonst der Microsoftcompiler am einfachste zu konfigurieren.

MacOS

Sinngemäß sind alle diese Schritte auch unter MacOS möglich. Da wir keine entsprechenden Geräte in der Arbeitsgruppe vorrätig haben, können wir hierzu keine eigene Anleitung geben; es gibt aber unzählige Blogs und Tutorials im Netz (wie auch zu all den anderen Platformen).


tl;dr – Wenn alles schief geht, installieren Sie einfach Ubuntu in eine virtuelle Maschine (z.B. mit VirtualBox). Dann ist es auf jeden Fall sehr einfach. Eine native Installation auf MacOS (welches das Interface eines BSD-Unix ) nach außen hat) ist aber nur minimal schwieriger.

Weitere Details: Komponenten für die Übersetzung von C++-Programmen

Um im allgemeinen besser zu verstehen, was für die Übersetzung eines C++-Programms benötigt wird, schauen wir uns die Komponenten an, die hier eine Rolle spielen:


Der Compiler selbst Bekannte/populäre Compiler sind


Aufruf des Compilers: Um den Compiler aufzurufen, kann man im einfachsten Fall den Kommandozeileninterpreter des Betriebssystems benutzen. Unter Windows ist das die "Eingabeaufforderung" (cmd.exe) oder die Powershell (wir schauen uns hier die einfachere cmd.exe an). Unter Linux stehen verschiedene Shells zur Verfügung, die bei einfachen Aufgaben alle sehr ähnlich funktionieren (bei Ubuntu startet man z.B. im GNOME Desktop das "Terminal", welches eine bash-shell bereitstellt).


Um den Compiler via Kommandozeile aufzurufen, muss das Program nicht nur auf dem System gespeichert sein; das OS muss es auch finden. Dazu gibt zwei Möglichkeiten:


Bibliotheken Um den Compiler nutzen zu können, benötigt man immer zusätzliche Bibliotheken. Immer deswegen, weil jedes Program eine sogenannte "Laufzeitbibliothek" einbinden muss, in der grundlegende Funktionen der Programmiersprache (wie z.B. Speicherverwaltung oder die Anbindung an das Betriebssystem) implementiert sind. Merke: Keine lib, kein Program.


Bibliotheken können auf gängigen Betriebssystemen auf zwei Arten eingebunden werden:




Verkürzt gesagt ist es am einfachsten, alle Bibliotheken statisch zu binden (das ist auch der Standard der Compiler). Bei dynamischer Bindung muss alles richtig installiert sein (in den Systempfaden eingetragen), damit die zusätzlichen Bibliotheken auch gefunden werden. Unter Windows kann man die nötigen DLLs auch einfach in das Programmverzeichnis kopieren, als "Quick-Fix". Unter Linux ist das aufwendiger (aber auch möglich).


Wie Bibliotheken eingebunden werden, wird beim Übersetzen mittels "Compilerflags" festgelegt. Mehr dazu in Kürze. Man kann es sich also grundsätzlich aussuchen.


Hilfsdateien für die Übersetzung mit Bibliotheken


Um ein Programm übersetzen zu können, braucht der Compiler zugriff auf weitere Hilfsdateien. Konkret sind dies



Wir diskutieren dies nun genauer.


Grundsätzlich werden bei der Übersetzung eines Programmabschnittes, welches eine Bibliothek nutzt, die Deklaration der Schnittstellen ("Interfaces") benötigt. Um dann dieses Programm (oder mehrere Teileprogramme) zu einem ausführbaren Gesamtprogram zu kombinieren ("Linken"), wird auch die Implementation der Bibliothek benötigt. In C++ sieht das folgendermaßen aus:


Includes: Schnittstellen liegen in sogenannten "Include files" (Dateiendung *.h auf allen Systemen). In der Regel sind diese für jede Bibliothek in einem Verzeichnis "include" gesammelt. Wir finden also typischerweise ein "include"-Verzeichnis für die C++-Laufzeitbibliothek (Teil der Compilerinstallation), ein "include"-Verzeichnis für Qt, usw. Damit der Compiler diese findet, muss man entweder explizit, per Kommandozeilen-Option, angeben, welche Verzeichnisse berücksichtigt werden sollen, oder man muss eine Umgebungsvariable setzen, in der eine Liste von Verzeichnissen angegeben ist.


Libs: Zur Übersetzung von statisch gebundenen Programmen braucht man zusätzlich zur Schnittstelle auch noch den Code der Bibliothek. Dieser liegt bei fertigen Bibliotheken in der Regel in sogenannten *.lib ("Library") Dateien. Auch hier muss dies dem Compiler bzw. Link als Commandozeilenparameter mit angegeben werden, oder man setzt eine entsprechend andere Umgebungsvarialbe. Unter Windows besteht eine Besonderheit: Zum dynamischen Binden wird zusätzlich eine spezielle *.lib-Datei benötigt, die als "Platzhalter" für die dynamische Bilbiothek, welche erst zur Laufzeit geladen wird, fungiert. Hier muss man also auch die richtigen "libs" angeben, um ein Programm dynamisch zu binden.


DLLs/SOs: Wenn ein dynamisch gebundenes Programm gestartet wird, dann müssen die entsprechenden Bibliotheksdateien vorliegen. Wie oben beschrieben muss dazu auch hier wieder eine Umgebungsvariable gesetzt sein (unter Linux und Windows ist dies recht unterschiedlich, wie oben bereits erklärt).


Mir dreht sich alles. Was soll ich nun tun?

Die Konfiguration ist insgesamt sehr aufwendig. Wir empfehlen daher das folgende Vorgehen:


Einfache Programme (ohne Qt, eine cpp-Datei):

g++ <DateinameQuelltext.cpp> -o <DateinameAusführbaresProgramm>
CL <DateinameQuelltext.cpp>

Komplexere Programme (mit Qt, oder mit mehreren cpp und h-Dateien):



Es ist selbstverständlich auch erlaubt, andere IDEs zu verwenden. Allerdings muss die Abgabe entweder


Falls Ihre IDE ein anderes Format benutzt, müssen Sie ggf. diese Dateien per Hand erstellen.


Für unerfahrende Programmierer/innen empfehlen wir die QtCreator IDE im QMAKE-Modus (QtCreator unterstützt auch CMAKE), da dies am einfachsten zu bedienen ist.


Das folgende Video zeigt ein Beispiel, wie ein etwas komplexeres Projekt, bestehend aus mehreren Modulen, mit QtCreator entwickelt wird (es sind einige Fehler eingebaut, die wir dann mit dem Debugger suchen; man bekommt damit einen ersten Eindruck, wie man mit der IDE arbeiten kann):


Benutzung von QtCreator für komplexere Projekte (24min)
P03-QtCreatorUsage.webm (1920x1080),
P03-QtCreatorUsage-small.webm (853x480)
Man findet das Video auch auf Panopto.









Datenschutz     Impressum