ALBERT-LUDWIGS-UNIVERSITÄT FREIBURG
INSTITUT FÜR INFORMATIK
Lehrstuhl für Mustererkennung und Bildverarbeitung
Prof. Dr.-Ing. Hans Burkhardt
|
Georges-Köhler-Allee Geb.052, Zi 01-029 D-79110 Freiburg Tel. 0761 - 203 - 8260 |
g++ example.cc -o exampleDabei werden alle vier oben beschriebenen Schritte ausgeführt und es ensteht das ausführbare Programm ,,example``. Ist der Sourcecode über mehrere Files verteilt (was auch schon bei kleineren Projekten unbedingt anzuraten ist) kann man diese mit
g++ example.cc classes1.cc classes2.cc -o exampleübersetzen. Das wird ziemlich schnell sehr zeitaufwendig, da bei jeder kleinen Änderung alle drei Source-Codes neu übersetzt werden müssen. Es ist besser, das Übersetzen und das Zusammenlinken zwei Schritten auszuführen. Um den g++ anzuweisen, nur die ersten drei Schritte der Compilierung auszuführen, muß man die Option ,,-c`` übergeben:
g++ -c example.cc -o example.o g++ -c classes1.cc -o classes1.o g++ -c classes2.cc -o classes2.o g++ example.o classes1.o classes2.o -o exampleWenn nun z.B. eine Änderung in classes1.cc vorgenommen wurde, so braucht nur der 2. und der 4. Befehl wiederholt zu werden. Die Entscheidung, welche Teile neukompiliert werden müssen, kann einfach anhand des jeweiligen Dateidatums gefällt werden. Ein Programm, das einem diese Arbeit abnimmt gibt es natürlich auch (siehe ,,make`` in Kapitel 3). Wichtig: Ein Source-Code muß natürlich auch dann neu kompiliert werden, wenn sich ein Header-File, daß mit #include eingefügt wird, ändert.
g++ -c example.cc -o example.o g++ -c classes1.cc -o classes1.o g++ -c classes2.cc -o classes2.o g++ example.o classes1.o classes2.o -o example -ltiffBeispiel 2: Nutzung der FFTW-Bibliothek3, die man im eigenen Home-Verzeichnis installiert hat (in /home/ronneber/include/fftw.h und /home/ronneber/lib/libfftw.a):
g++ -c -I/home/ronneber/include/ example.cc -o example.o g++ -c -I/home/ronneber/include/ classes1.cc -o classes1.o g++ -c -I/home/ronneber/include/ classes2.cc -o classes2.o g++ -L/home/ronneber/lib example.o classes1.o classes2.o -o example -lfftwWenn man mehrere Bibliotheken einbindet, muß man unbedingt auf die richtige Reihenfolge achten. Jede Bibliothek kann nur die Funktionen der weiter hinten definierten nutzen. Beispiel: Die ,,fftw_threads`` - Bibliothek benötigt Funktionen aus der ,,pthread`` Bibliothek. Dann muß man beim Linken
-lfftw_threads -lpthreadsangeben. Nicht andersherum, dann findet der Linker die Funktionen nicht. Das dem so ist, ist übrigens Absicht. Andernfalls wäre es nicht möglich nur einige Funktionen aus einer Bibliothek mit einer eigenen Bibliothek zu überschreiben.
g++ -c classes1.cc -o classes1.o g++ -c classes2.cc -o classes2.o ar -rcv libhurz.a classes1.o classes2.o ranlib libhurz.aDas Programm ,,ar`` hängt einfach die angegebenen Object-Files zusammen und erstellt einen Index, mit dem die Original-Files wieder hergestellt werden könnten. ,,ranlib`` extrahiert die Symbol-Tables der einzelnen Object-Files und faßt sie in einem großen Symbol-Table zusammen. Dies beschleunigt nachher das Linken, ist aber nicht unbedingt notwendig. Zum Einbinden dieser eigenen Bibliothek gilt dasselbe wie im vorigen Kapitel, um also unser example-Programm nun zu erstellen, schreiben wir nur noch
g++ -I/home/ronneber/hurz/include -c example.cc -o example.o g++ -L/home/ronneber/hurz/lib example.o -o example -lhurz
strip examplekönnen nachträglich alle überflüssigen Symbol-Tables und Debugging-Informationen von einem Programm entfernt werden, wodurch es üblicherweise wesentlich kleiner wird. Man muß also nicht neu kompilieren, nur um ein Programm ohne Debugging-Informationen zu haben.
Um den Quellcode eines Programms in einen ausführbaren Zustand -- ausführbare Binärdatei -- zu überführen sind verschiedenste Schritte notwendig. Zunächst einmal müssen alle Quelldateien des Programms vom Compiler in einen Objektcode überführt werden. Einige Objektdateien werden vielleicht zu Bibliotheken zusammengeführt. Schlußendlich müssen alle Objektdateien und Bibliotheken zu einer Binärdatei zusammengebunden (gelinkt) werden.
Diese Arbeitsschritte sind je nach Umfang des Softwarepaketes recht komplex und zeitaufwendig. Sicherlich ließen sich die Befehle statisch in ein Skript codieren. Doch würde der Zeitaufwand immer noch immens sein, wenn immer alle Quelldateien neu übersetzt werden müßten. Auch, wenn sich nur eine Quelldatei geändert hat. Sinnvoller und auch Ressourcen sparender wäre ein Werkzeug, das erkennt, welche Quelldateien neu compiliert, oder welche Bibliotheken neu gebildet werden müssen.
Genau dafür wurde das Werkzeug make4 entwickelt. Mit dem Programm make ist es möglich, Abhängigkeiten zwischen beliebigen Dateien (z.B. Quelldateien und Objektdateien) zu definieren und Abbildungsvorschriften anzugeben, die einen Dateityp in einen anderen überführen (z.B. *.cc in *.o).
In diesem Kapitel wird eine kurze Einführung zu make gegeben. Es ist nur eine kurze Einführung, da das make-Werkzeug von so großer Komplexität ist, daß eine ausführliche Beschreibung den Rahmen dieser Anleitung sprengen würde.
Im allgemeinen erwartet make eine Datei mit dem Namen Makefile, die im aktuellen Arbeitsverzeichnis steht. In der Datei Makefile ist definiert, was make machen soll. Beim Aufruf vom make liest das Programm das Makefile ein und interpretiert es. Soll make eine Datei mit einem anderen Name als Makefile nehmen, so läßt sich make mit dem Parameter -f NameOfMakefile aufrufen.
Damit make weiß, was es machen soll, sind in der Makefile-Datei Regeln definiert. Alle Regeln in einem Makefile müssen folgender Syntax genügen:
Ziel ... : Abhängigkeiten ... <TAB>Befehl <TAB>...
Demnach ist ein Ziel abhängig von seinen Abhängigkeiten. Wie das Ziel gebildet wird, steht in den Befehlszeilen darunter. Eine Regel kann auch nur aus Ziel und Abhängigkeiten bestehen. Ferner kann ein Ziel auch ohne Abhängigkeiten definiert sein, das nur Befehlszeilen beinhaltet.
Das Tabulatorzeichen zu Beginn jeder Befehlszeile ist obligatorisch. Fehlt das Zeichen, wird sich make bitterlich beschweren und die Ausführung des Makefiles abbrechen. Das Kommentarzeichen für ein Makefile ist das #-Zeichen.
Soll make nur ein Ziel erzeugen, muß make das Ziel in der Kommandozeile als Parameter mitgegeben werden. Ansonsten wird make versuchen, alle Regel zu befolgen.
make unterscheidet zwischen impliziten und expliziten Regeln. Implizite Regel sind Regeln, die make schon kennt und nicht definiert werden müssen. Zum Beispiel kann make eine C-Quelldatei *.c in eine Objektdatei *.o durch Compilation überführen. Explizite Regeln sind in dem Makefile definiert.
Für mehr Klarheit soll das folgende Beispiel sorgen. Ein Programm myprg soll aus drei Quelldateien first.cc, second.cc und myprg.cc gebildet werden. Das dazugehörige Makefile sieht wie folgt aus:
myprg : myprg.o first.o second.o g++ myprg.o first.o second.o -o myprg myprg.o : myprg.cc first.hh second.hh basics.hh g++ -c myprg.cc first.o : first.cc first.hh g++ -c first.cc second.o : second.cc second.hh g++ -c second.cc clean : rm -f myprg myprg.o first.o second.o rebuild : clean myprg
Nun soll make das Programm myprg erzeugen. Dafür wird make ohne Parameter aufgerufen. Das make-Programm liest das Makefile ein und interpretiert es. In Abhängigkeit existierender Dateien führt es die Regeln aus.
Zu Beginn gehen wir von der Existenz aller Quelldateien (*.cc und *.hh) aus. Die Objektdateien (*.o) und die Programmdatei myprg sollen noch nicht erzeugt worden sein.
In der ersten Regel des Makefiles ist definiert, wovon die Binärdatei myprg abhängt und wie das Programm gebildet wird. Demnach müssen für das Linken des Programms zunächst alle Objektdateien myprg.o, second.o und first.o generiert werden. Um das zu erfüllen sucht make jetzt nach Regeln für die Erzeugung der Objektdateien.
In der zweiten bis vierten Regel ist definiert, wie make die Objektdateien, die für das Ziel myprg notwendig sind, erzeugen kann. Zum Beispiel ist die Objektdatei myprg.o auf die Quelldatei myprg.cc und den Headern first.hh, second.hh und basics.hh angewiesen. An dieser Stelle kann make die erste Regel erfüllen, da die Abhängigkeiten als Dateien existieren, und nicht erst gebildet werden müssen. D.h. make führt den Befehl gcc -c myprg.cc -o myprg.o aus und erzeugt so die Objektdatei myprg.o. Sukzessive werden so alle Objektdateien nacheinander -- in der Reihenfolge wie es in der ersten Regel definiert ist -- erzeugt.
make wird nun die Befehlszeile der ersten Regel ausführen, da die Abhängigkeiten erfüllt wurden. Mit der Befehlszeile werden alle Objektdateien zum Hauptprogramm myprg.o gelinkt und das ausführbare Programm myprg ist erzeugt.
Die vorletzte Regeln mit dem Ziel clean dient dem Aufräumen. Möchte man das Programm von Grund auf neu generieren, sorgt die Regel clean für das Löschen aller Objektdateien und der Programmdatei. Der Aufruf der Regel erfolgt mit make clean.
Um das Neuerzeugen noch weiter zu vereinfachen gibt es noch die Regel mit dem Ziel rebuild. Wird make mit dem Ziel rebuild aufgerufen, wird zunächst clean und dann myprg ausgeführt.
Wir nun zum Beispiel die Quelldatei second.cc geändert und anschließend der make-Befehl aufgerufen, so passiert folgendes: make liest wiederum das Makefile ein und schaut, ob alle Ziele erfüllt wurden. Bei der Regel mit dem Ziel second.o bemerkt das make-Programm, daß die Quelldatei second.cc ein aktuelleres Datum als die Objektdatei second.o hat. Ergo kann die Objektdatei nicht von der aktuellen Version der Quelldatei stammen. Somit führt make die zugehörige Befehlszeile aus und compiliert second.cc neu. Bis auf die erste Regel sind nun alle anderen Regeln erfüllt. Am Schluß bindet make alle Objektdateien zu einer neuen Version von myprg zusammen und terminiert. Es wurde nur die Arbeit vollzogen, die notwendig war.
Das zuvor diskutierte Beispiel für ein Makefile ist natürlich noch etwas unbeholfen. Und zwar deshalb, weil die Regeln für das Erzeugen der Objektdateien explizit für alle Dateien hingeschrieben wurde. Ferner wurden keinerlei Variablen verwendet. Soll z.B. der Compiler gcc ersetzt werden, oder ein zusätzlicher Parameter zum Aufruf zugefügt werden, müssen alle betreffenden Zeilen editiert werden.
Generell lassen sich Variablen in einem Makefile mit
VAR = WERTdefinieren. Verwendet werden Variablen in einem Makefile mit
$(VAR).
Im folgenden Beispiel werden Compiler (CXX), Compilerparameter (CXXFLAGS), Linker (CC) und Objektdateien (OBJS) in Variablen definiert und verwendet. Ferner werden die impliziten Regeln von make für C++ Quellen (*.o:*.cc) verwendet:
OBJS = myprg.o first.o second.o CXX = g++ CC = $(CXX) CXXFLAGS = -Wall all : myprg myprg : $(OBJS) myprg.o first.o : first.hh myprg.o second.o : second.hh myprg.o : basics.hh clean : rm -f myprg $(OBJS) rebuild : clean myprg
Die Variablen CXX, CC und CXXFLAGS werden von den impliziten Regeln für C++ Übersetzung und Bindung verwendet. So teilt CXXFLAGS mit dem Flag -Wall dem Compiler mit, daß wirklich alle Warnungen ausgegeben werden sollen. Beim Aufruf von make wird, wie schon zuvor erklärt, versucht alle Regeln zu erfüllen. Wie make eine Objektdatei generiert ist in der impliziten Regel für *.o:*.cc erklärt. Um eine Quelldatei in eine Objektdatei abzubilden führt make den Befehl:
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)aus. Die Abhängigkeiten der Objektdateien von den Headern steht nach wie vor in dem Makefile. Allerdings sind die Abhängigkeiten diesmal zusammengefaßt. Das Linken der Objektdateien wird über die folgende implizite Regel realisiert:
$(CC) $(LDFLAGS) Objektdateien $(LOADLIBES)Die Verwendung von Variablen und impliziten Regeln führt somit zu wesentlich kompakteren Makefiles. Einen Katalog der impliziten Regeln findet man in der Anleitung zum GNU make (siehe Abschnitt Referenzen).
http://www.gnu.org/software/make/make.html
http://www.gnu.org/manual/make/index.html
Emacs ist ein sehr leistungsfähiger und selbstdokumentierender Editor der aus einem Lisp-Interpreter mit Funktionen zur Textverarbeitung besteht. Emacs ist dadurch sehr flexibel an verschiedene Benutzeranforderungen anpaßbar und kann nahezu unbegrenzt, und ohne die Notwendigkeit einer Neukompilation, erweitert werden.
Ein wichtiges Grundkonzept von Emacs sind ,,Buffer``. Dies sind voneinander getrennte Arbeitsbereiche, in denen völlig unterschiedliche Dinge vor sich gehen können. Ein Buffer kann z.B. C++-Quellencode beinhalten, aber auch eine ,,Verzeichnisstruktur``, eine ,,Shell``, einen ,,Debugger`` oder einen ,,Compiler``.
Die Buffer sollten nicht mit den verschiedene ,,Frames`` (Fenstern) verwechselt werden. In den Frames werden ein oder mehrere Buffer angezeigt, was aber nicht bedeutet, daß ein Buffer der nicht angezeigt wird, nicht mehr existiert.
Ein weiteres wichtiges Grundkonzept sind die Modi, die es erlauben das Verhalten von Emacs an verschiedenen Bufferinhalte anzupassen. Im C++-Mode ist z.B. eine automatische Einrückung des Quellencodes mit Tab und die xfarblich Hervorhebung von Schlüsselwörtern möglich.
Vor dem Aufrufen muß in der Shell der Befehl module add emacs ausgeführt werden. Aufgerufen wird Emacs dann mit: emacs filename, wobei filename nicht mit angegeben werden muß.
Für Neubenutzer bietet das Tutorial, welches mit C-h t (bei gedrückter Control-Taste die h-Taste drücken und dann die t-Taste alleine drücken) aufgerufen wird, einen schnellen Einstieg.
Zusätzlich zur im Tutorial beschriebenen Online-Hilfe (über die man sich mit C-h ? eine Übersicht verschaffen kann) können mit C-h i die Info-Files konsultiert werden. Das komplette Handbuch kann unter http://www.gnu.org/manual/emacs-20.3/emacs.html gefunden werden. Eine einseitige Zusammenfassung der wichtigsten Befehle (die Reference-Card) steht unter http://www.refcards.com/ zur Verfügung.
Die Konfiguration von Emacs geschieht durch Editieren der Datei .emacs im Homeverzeichnis des Users, die beim Aufstarten von Emacs eingelesen wird.
Wenn zum Beispiel die Funktion dabbrev-expand, die praktisch ist um z.B. lange Variablenname nach Eingabe von ein paar Zeichen automatisch zu komplettieren, mit S-iso-lefttab (gleichzeitiges Drücken der Shift- und der Tabulatortaste) anstatt des auf der deutschen Tastatur weniger praktischen M-/ aufgerufen werden soll, kann dies durch Eintragen der folgenden Zeile in .emacs erreicht werden:
(global-set-key [S-iso-lefttab] 'dabbrev-expand)
-g
. Folgender Aufruf erzeugt
z.B.
eine solche Datei.
g++ -g myfile.cc -o myfileAuf ein solches Programm kann der GDB sofort angewandt werden. Gestartet wird er via
gdb
,
notwendige Kommandos, um das Programm zu debuggen sind
ulimit -awerden die Speichergrenzen für diverse Größen angezeigt. Unter
coredump
muss ein positiver Eintrag stehen, damit Coredumps
erzeugt werden. Dies kann (in den meisten Shells) via
ulimit -c coresizeeingestellt werden, wobei
coresize
die gewünschte Größe in
Bytes darstellt.
Hat ein Fehlerhaftes Programm anschließend ein Corefile erzeugt, kann
die Absturzstelle mit GDB ermittelt werden, indem nach normalem
Starten von GDB und Festlegen des zu inspizierenden (abgestürzten)
Programms mit file, das Corefile geladen wird. hierzu dient der
Befehl
Das Concurrent Versions System (CVS) dient zur Versionsverwaltung kompletter und ggf. mehrstufiger Datei-Verzeichnisse, wie sie üblicherweise in größeren Software- oder Konfigurationsprojekten entstehen. CVS baut intern auf das sogenannte Revision Control System (RCS) auf und benutzt eine ähnliche Begriffswelt wie RCS. Im Gegensatz zu RCS sind jedoch keine expliziten Sperren auf Dateien möglich, so daß auch mehrere Personen die gleiche Datei ändern (oder gar löschen) können. Etwaige Konflikte, die bei den meisten Projekten erfahrungsgemäß jedoch selten auftreten, werden später aufgelöst.
Die Grundidee bei CVS ist, daß es ein zentrales Repository (auf deutsch: Lagerstätte) gibt, in dem der gesamte Dateibaum verschiedener Projekte mit den dazugehörigen Verzeichnissen, Dateien und deren Versionen abgelegt ist. Jeder Benutzer erzeugt mit Hilfe von CVS eine private Arbeitskopie (oder auch mehrere) eines zu einem Projekt gehörenden Dateibaums. Hier kann er die Dateien beliebig ändern, sowie neue Dateien und Verzeichnisse erzeugen oder auch veraltete Dateien und Verzeichnisse entfernen. Nachdem er seine Änderungen vorgenommen hat, muß er diese zunächst mit der Version im Repository abgleichen und anschließend in das Repository eintragen, nachdem er ggf. Konflikte mit den Änderungen anderer Benutzer aufgelöst hat. Hilfreich ist hier oft, sich zunächst die eigenen Änderungen nochmals anzusehen, insbesondere, wenn mehrere Dateien betroffen sind.
Anmerkungen: CVS wird fast vollständig durch den Befehl cvs(1) gesteuert. Die eigentlichen Aktionen von CVS werden durch Kommandonamen gesteuert, die als erster Parameter auf der Kommandozeile dem Befehlswort cvs folgen (s.u.). An verschiedenen Stellen werden Versionsnummern und Bezeichner benötigt und benutzt, auf die wir hier aber nicht weiter eingehen.
Das Programm cvs muß der Shell bekannt gemacht werden. Das geschieht in unserer Umgebung durch die Eingabe von
idefix: $ module add cvs
Ein neues Repository wird angelegt, indem man (an beliebiger Stelle) ein Verzeichnis anlegt, die Environment-Variable CVSROOT darauf einstellt, in dieses wechselt und dann das Kommando init ausführt:
idefix: $ mkdir /sw-praktikum/cvsroot
idefix: $ cd /sw-praktikum/cvsroot
idefix: $ setenv CVSROOT /sw-praktikum/cvsroot
idefix:/sw-praktikum/cvsroot $ cvs init
Man beginnt ein neues Projekt, indem man in einem beliebigen Verzeichnis work_dir (nicht in CVSROOT!) mindestens ein neues Verzeichnis anlegt, ggf. auch weitere Unterverzeichnisse des neuen Projekts. Anschließend wechselt man wieder nach work_dir und ruft dort das CVS-Kommando import auf. Dabei werden drei weitere Parameter nötig:
idefix:... $ mkdir my_proj
idefix:... $ cd my_proj
idefix:.../my_proj $ mkdir src
idefix:.../my_proj $ mkdir include
idefix:.../my_proj $ cvs import new_proj start_it developer_0
cvs import: Importing $CVSROOT/new_proj/src
cvs import: Importing $CVSROOT/new_proj/include
->$CVSEDITOR
No conflicts created by this import
Nachdem man die Environment-Variable $CVSROOT auf den Pfad des Repositories eingestellt hat, kann man mit dem CVS-Kommando checkout im aktuellen Verzeichnis eine Kopie der aktuellen Version des Dateibaums von einem im Repository abgelegten Projekt erzeugen (hier z.B. test):
idefix:/... $ cvs checkout test
cvs checkout: Updating test
U test/file
Nun können die bestehenden Dateien geändert (bzw. neue angelegt oder veraltete gelöscht) werden:
idefix:/... $ cd test
idefix:/.../test $ $EDITOR file
Anmerkung: CVS legt im Arbeitsverzeichnis (und in allen Unterverzeichnissen) zusätzliche Verzeichnisse mit dem Namen CVS an. Diese und die darin enthaltenen Dateien dürfen nicht manipuliert werden!
Nach erfolgter Änderung werden die Dateien mit dem CVS-Kommando update mit der Version im Repository verglichen. Hierbei wird insbesondere geprüft, ob seit dem letzten Abgleich (oder checkout) Dateien durch andere Benutzer geändert wurden. Existieren solche Änderungen, werden sie automatisch in der eigenen Arbeitskopie nachgetragen. Falls dabei Konflikte auftreten, z.B. weil zwei Benutzer an der gleichen Stelle einer Datei geändert haben, so müssen diese zunächst aufgelöst werden.
idefix:/.../test $ cvs update
cvs update: Updating .
M file
Es wird für jede Datei, die von Änderungen betroffen ist, ihr Name ausgegeben und ein Indikator (Buchstabe am Anfang der Zeile), der die Änderung beschreibt:
Treten keine Konflikte auf, bzw. sind diese behoben, so werden die Änderungen endgültig mit dem CVS-Kommando commit ins Repository eingetragen. Dabei wird für die geänderten Dateien ein Editor (Environment-Variable $CVSEDITOR bzw. $EDITOR) geöffnet, in den man seine Anmerkungen zu den Änderungen eintragen kann:
idefix:/.../test $ cvs commit
cvs commit: Examining .
cvs commit: Committing .
->$CVSEDITOR
Checking in file;
$CVSROOT/test/file,v <- file
new revision: 1.2; previous revision: 1.1
done
Achtung: Wurden die Konflikte nach einem update-Kommando nicht aufgelöst, so werden die Dateien mit Konfliktmarkierungen (s. Konflikte auflösen) ins Repository übertragen. Das Arbeitsverzeichnis bleibt durch den Befehl commit erhalten, es kann einfach gelöscht werden, falls es nicht mehr gebraucht wird.
Hat man, z.B. mit dem Editor, eine neue Datei angelegt, so muß diese mit dem CVS-Kommando add beim Repository angemeldet werden.
idefix:/.../test $ $EDITOR newfile
idefix:/...;/test $ cvs add newfile
cvs add: scheduling file `newfile' for addition
cvs add: use 'cvs commit' to add this file permanently
Die endgültige Übernahme erfolgt erst bei einem commit:
idefix:/.../test $ cvs commit
cvs commit: Examining .
cvs commit: Committing .
RCS file: $CVSROOT/test/newfile,v
done
->$CVSEDITOR
Checking in newfile;
$CVSROOT/test/newfile,v <- newfile
initial revision: 1.1
done
Dateien bzw. Verzeichnisse können durch das CVS-Kommando remove aus dem Repository gelöscht werden, wenn sie auch im Arbeitsverzeichnis gelöscht wurden (bei Verzeichnissen erst deren Dateien aus dem Repository löschen, ggf. rekursiv).
idefix:/.../test $ rm file
idefix:/.../test $ cvs remove file
cvs remove: scheduling `file' for removal
cvs remove: use 'cvs commit' to remove this file permanently
Auch hier erfolgt die endgültige Löschung erst durch ein commit (Die Dateien werden nicht wirklich im Repository gelöscht, sondern nur als gelöscht markiert, da man jederzeit eine alte Version des Projektes wieder herstellen können muß):
idefix:/.../test $ cvs commit
cvs commit: Examining .
cvs commit: Committing .
->$CVSEDITOR
Removing file;
$CVSROOT/test/file,v <- file
new revision: delete; previous revision: 1.2
done
Oft will sich der Benutzer vor einem commit nochmals die Änderungen ansehen, die er vorgenommen hat. Hier gibt es das CVS-Kommando diff, das auf dem UNIX-Befehl diff(1) aufbaut und auch die gleichen Optionen hat. In diesem Fall werden Änderungen mit einem ! eingeleitet:
idefix:/.../test $ cvs diff -bc
cvs diff: Diffing .
Index: file
===================================================================
RCS file: $CVSROOT/test/file,v
retrieving revision 1.1
diff -b -c -r1.1 file
*** file 1998/01/20 00:03:59 1.1
-- file 1998/01/21 08:15:21
***************
*** 3,9 ****
#
# test CVS - history at end
! testfile
#
# Revision 1.4 2000/01/13 08:25:19 duda
# Seitenfuss vereinheitlicht
#
# Revision 1.3 2000/01/12 09:56:11 duda
# ISA->VS
#
# Revision 1.2 1998/07/01 09:35:28 ascheman
# Rück-Verweis auf CVS-Hauptseite eingeführt
#
# Revision 1.1 1998/04/20 11:13:39 ascheman
# Initial revision
#
-- 3,10 --
#
# test CVS - history at end
! changed one line
! to two lines!
#
# Revision 1.4 2000/01/13 08:25:19 duda
# Seitenfuss vereinheitlicht
#
# Revision 1.3 2000/01/12 09:56:11 duda
# ISA->VS
#
# Revision 1.2 1998/07/01 09:35:28 ascheman
# Rück-Verweis auf CVS-Hauptseite eingeführt
#
# Revision 1.1 1998/04/20 11:13:39 ascheman
# Initial revision
#
Treten bei dem Kommando update Konflikte auf, z.B.
idefix:/.../test $ cvs update
cvs update: Updating .
RCS file: $CVSROOT/test/newfile,v
retrieving revision 1.1
retrieving revision 1.2
Merging differences between 1.1 and 1.2 into newfile
rcsmerge: warning: conflicts during merge
cvs update: conflicts found in newfile
C newfile
die nicht von CVS automatisch aufgelöst werden können (Dateien, die mit dem Indikator C gekennzeichnet sind), so passiert folgendes:
<<<<<<< newfile
Conflict from local file!
=======
Conflict from repository!
>>>>>>> 1.2
Die Konflikte müssen dann in der Arbeitsdatei manuell aufgelöst werden. Anschließend muß die Datei (oder die Dateien) wieder mit den Befehlen update und commit ins Repository übertragen werden.
Die meisten CVS Kommandos lassen sich komfortabel im Emacs ausführen.
Als Vorbereitung muß dafür (vor dem Start des emacs) in der Shell der Befehl
module add emacs
ausgeführt werden. Folgende Zeile ist außerdem in die Datei /.emacs zu übernehmen:
(autoload 'cvs-update "pcl-cvs" nil t)
Der CVS-Modus kann dann durch den Emacs-Befehl
M-x cvs-update
aktiviert werden. Hilfe zu den verfügbaren Kommandos gibt anschließend die Eingabe eines ?.
Alternativ dazu kann auch der Menüpunkt ToolsVersion Control verwendet werden.
CVS kann auch von einem Heimarbeitsplatzrechner verwendet werden. Zunächst muss man gewährleisten, dass eine ordnungsgemäße ssh-Verbindung vom Heimarbeitsplatz zu dem CVS-Server aufgebaut werden kann. Näheres dazu unter man ssh, man ssh-keygen.
Weiterhin müssen folgende Variablen (auf dem Heimarbeitsplatz) gesetzt werden:
heimrechner: $ setenv CVSROOT USERNAME@SERVERNAME:/sw-praktikum/cvsroot
heimrechner: $ setenv CVS_RSH ssh
USERNAME steht für den Uni-Account, als SERVERNAME
kann
miraculix.informatik.uni-freiburg.de eingesetzt werden.
Anschließend kann wie gewohnt durch den Befehl
heimrechner: $ cvs checkout test
eine Arbeitskopie erzeugt werden.
Die hier beschriebene Kurzanleitung orientiert sich zu einem großen
Teil an
http://www.informatik.tu-darmstadt.de/VS/Rechner/Software/Cvs/Kurz.html
Weitere Referenzen lassen sich ausgehend von http://www.cvshome.org lesen.
Weiterhin stehen im Labor die Handbücher ,,Version Management with CVS``, ,,User's Guide to pcl-cvs--the Emacs Front-End to CVS`` und ,,CVS Quick Reference Card`` bereit.
module add doxygen module add gvDie gesamten Optionen zur Funktionsweise von Doxygen müssen in einem Konfigurationsfile angegeben werden, das ähnliche Struktur wie ein Makefile hat. Ein solches Default-Konfigurationsfile wird erzeugt, indem Doxygen mit der -g Option aufgerufen wird:
doxygen -g <conffile>Anschließend kann die Datei
<conffile>
mit einem
beliebigen Editor bearbeitet werden, oder man verwendet die grafische
Oberfläche doxywizard , die über nützliche
Hilfekommentaren zu den einzelnen Einträgen verfügt.
Die minimal anzugebenden Optionen sind
/*! text */
bzw. die
Einzelzeilenvariante //! text
können Kommentarblöcke definiert werden, die von Doxygen
bearbeitet werden. Innerhalb dieser Blöcke kann beliebiger freier Text
und eine Vielzahl von Schlüsselwörter verwendet werden.
Für alle Bestandteile wie Dateien, Klassen, Methoden, Variablen,
Funktionen etc. ist eine solche Dokumentation möglich und sinnvoll.
Grundsätzlich ist für jedes dieser Objekte eine Kurzdokumentation
(durch die Einzeilenvariante) und
eine detailliertere Dokumentation (durch einen Kommentarblock)
möglich.
Ist eine Kurzdokumentation länger als eine Zeile, muß diese
innerhalb des Detaildokumentationsblocks durch das Kommando
\brief
definiert werden. Der gesamte Text bis zur nächsten
Leerzeile wird dabei als Kurzdokumentation aufgefaßt.
Die Kommentarblöcke stehen grundsätzlich vor den Definitionen
oder Deklarationen. In Einzelfällen ist eine andere Position sinnvoll.
Eine Referenz auf das vorhergehenden Objekt kann z.B. durch die
Einzeilenvariante via
//!< text
hergestellt werden. Dies macht bei Variablen Sinn,
die nur einer kurzen Erläuterung bedürfen, ein Beispiel folgt unten.
Will man einen Kommentarblock vollkommen von der Definition oder der
Deklaration eines Objektes lösen, muß der Bezug des Blocks zu dem
Objekt hergestellt werden mittels dem entsprechenden Schlüsselwort
\class, \struct, \union, \enum, \fn, \var,
\def,
\file
oder \namespace
und anschließendem Objektnamen.
Grundsätzlich sollen public
-Komponenten in den Header-Dateien
dokumentiert werden, private
-Komponenten stattdessen in den
zugehörigen Quelldateien.
Einige Schlüsselwörter, die in den Blöcken verwendet werden
sollen, sind:
\param <parname> <description>
: Dokumentation von
Funktionsparametern.
\exception <exname> <description>
: Dokumentation
möglicher Exceptions.
\return <description>
: Dokumentation des Rückgabewertes
einer Funktion.
/*! *************************************************************** ** ** \file dummyclass.hh ** \brief provides dummy class for demonstration of ** doxygen-functionality. ** ****************************************************************/ #include <parentclass.hh> //! brief description of Dummyclass. /*! More detailed description can be longer. */ class DummyClass : public ParentClass { public: /*! \brief a brief description can also last over several lines * as shown in this example of a constructor. * * detailed description of the constructor: * creates new Dummyclass Instance. * * \param param1 some initialization parameter * \param name name of the instance. * * \exception DummyClassException the possible exceptions */ DummyClass(const int param1, const char *name); //! calculation of some reasonable value. /*! * \param param1 some necessary parameter for calculation * * \return the result of the calculation */ int calc_something(const int param1); /*! a public variable containing one property. */ int property1; float property2; //!< this is a backward-reference documentation line. };
This document was generated using the LaTeX2HTML translator Version 98.1p5 (May 15th, 1998)
Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
The command line arguments were:
latex2html -no_navigation -split 0 doku.tex
The translation was initiated by Dachuan Cheng on 2001-04-30