Kapitel 12. Programmierung

# Kapitel 12. Programmierung

Ich gebe hier einige Startimpulse, um Programmierung im Debian-System zumindest so weit zu erlernen, dass der Programmcode aus Debian-Quellpaketen zwecks Fehlersuche nachverfolgt werden kann. Hier einige erwähnenswerte Pakete und dazugehörige Dokumentation:

Handbuchseiten (manpages) sind verfügbar, indem Sie nach Installation der `manpages`- und `manpages-dev`-Pakete "`man programmname`" eingeben. Informationen über GNU-Werkzeuge erhalten Sie über "`info programmname`" nach Installation der entsprechenden Dokumentationspakete. Sie müssen unter Umständen die Bereiche `contrib` und `non-free` des Archivs zusätzlich zu `main` freigeben, da einige GFDL-Dokumentation als nicht DFSG-frei angesehen wird.

Ziehen Sie bitte die Nutzung eines Versionskontrollsystems in Erwägung, siehe Abschnitt 10.5, „Git“.

| Warnung
Verwenden Sie nicht "`test`" als Namen für eine ausführbare Testdatei. "`test`" ist ein fest integrierter Shell-Builtin.

| Achtung
Sie sollten Software, die direkt aus den Quellen kompiliert wurden, in "`/usr/local`" oder "`/opt`" installieren, um Kollisionen mit Systemprogrammen zu vermeiden.

| Tipp
Die Code-Beispiele zum Erzeugen des Songs "99 Bottles of Beer" sollten Ihnen gute Ideen zu nahezu allen Programmiersprachen liefern.

## 12.1. Das Shell-Skript

Das Shell-Skript ist eine Textdatei mit gesetztem Ausführungsbit und enthält Befehle in der folgenden Form:

    #!/bin/sh
     ... command lines

Die erste Zeile spezifiziert den Shell-Interpreter, der den Inhalt dieser Datei liest und ausführt.

Das Lesen von Shell-Skripten ist der beste Weg, um zu verstehen, wie ein Unix-artiges System arbeitet. Ich gebe hier einige Hinweise zur Shell-Programmierung. Lesen Sie "Shell Mistakes" (https://www.greenend.org.uk/rjk/2001/04/shell.html), um aus Fehlern zu lernen.

Anders als der interaktive Shell-Modus (lesen Sie Abschnitt 1.5, „Der einfache Shell-Befehl“ und Abschnitt 1.6, „Unix-ähnliche Textverarbeitung“) verwenden Shell-Skripte häufig Parameter, bedingte Ausdrücke und Schleifen.

### 12.1.1. POSIX-Shell-Kompatibilität

Viele Systemskripte können von jeder POSIX-konformen Shell (lesen Sie Tabelle 1.13, „Liste von Shell-Programmen“) interpretiert werden.

- Die nicht-interaktive Standard-POSIX-Shell "`/usr/bin/sh`" ist ein symbolischer Link auf `/usr/bin/dash` und wird von vielen Systemprogrammen genutzt.

- Die interaktive Standard-POSIX-Shell ist `/usr/bin/bash`.

Vermeiden Sie, in Shell-Skripten Bashisms oder Zshisms (speziell für Bash oder Zsh angepasste Shell-Befehle) zu verwenden, damit sie auf alle POSIX-Shells portierbar sind. Sie können dies mittels checkbashisms(1) überprüfen.

Tabelle 12.1. Liste typischer Bashisms

Gut: POSIX | Vermeiden: Bashism
--- | ---
`if [ "$foo" = "$bar" ] ; then …` | `if [ "$foo" == "$bar" ] ; then …`
`diff -u datei.c.orig datei.c` | `diff -u datei.c{.orig,}`
`mkdir /foobar /foobaz` | `mkdir /foo{bar,baz}`
`funktionsname() { … }` | `function funktionsname() { … }`
Oktalformat: "`\377`" | Hexadezimalformat: "`\xff`"

Der Befehl "`echo`" muss mit Vorsicht verwendet werden, da seine Implementierung sich zwischen Shell-Builtins und externen Befehlen unterscheidet:

- vermeiden Sie die Verwendung jeglicher Befehlsoptionen außer "`-n`";

- vermeiden Sie die Verwendung von Escape-Sequenzen in Zeichenketten, da deren Handhabung unterschiedlich ist.

| Anmerkung
Obwohl die Option "`-n`" nicht wirklich der POSIX-Syntax entspricht, ist sie grundsätzlich akzeptiert.

| Tipp
Nutzen Sie den "`printf`"-Befehl statt "`echo`", wenn Sie Escape-Sequenzen in auszugebenen Zeichenketten einbetten möchten.

### 12.1.2. Shell-Parameter

Einige spezielle Shell-Parameter werden oft in Shell-Skripten verwendet:

Tabelle 12.2. Liste von Shell-Parametern

Shell-Parameter | Wert
--- | ---
`$0` | Name der Shell oder des Shell-Skripts
`$1` | erstes (1.) Shell-Argument
`$9` | neuntes (9.) Shell-Argument
`$#` | Anzahl der Parameter
`"$*"` | `"$1 $2 $3 $4 … "`
`"$@"` | `"$1" "$2" "$3" "$4" …`
`$?` | Beendigungs-Status des zuletzt ausgeführten Befehls
`$$` | Prozessnummer (PID) des Shell-Skripts
`$!` | PID des zuletzt ausgeführten Hintergrundbefehls

Grundlegende Parameterauswertungen, die Sie sich einprägen sollten:

Tabelle 12.3. Liste von Parameterauswertungen

Parameterauswertung | Wert, falls `var` gesetzt ist | Wert, falls `var` nicht gesetzt ist
--- | --- | ---
`${var:-string}` | "`$var`" | "`string`"
`${var:+string}` | "`string`" | "`null`"
`${var:=string}` | "`$var`" | "`string`" (und ausführen von "`var=string`")
`${var:?string}` | "`$var`" | Ausgabe von "`string`" auf stderr (und mit Fehlerstatus beenden)

Hierbei ist der Doppelpunkt "`:`" in allen Operatoren optional:

- mit "`:`" = Operatortest für existiert und nicht Null;

- ohne "`:`" = Operatortest nur für existiert.

Tabelle 12.4. Liste von Shell-Parameterersetzungen

Parameterersetzung | Ergebnis
--- | ---
`${var%suffix}` | entferne kleinstes Suffix-Muster
`${var%%suffix}` | entferne größtes Suffix-Muster
`${var#prefix}` | entferne kleinstes Prefix-Muster
`${var##prefix}` | entferne größtes Prefix-Muster

### 12.1.3. Bedingte Ausdrücke in der Shell

Jeder Befehl gibt einen Beendigungs-Status (Exit-Status) zurück, der für einen bedingten Ausdruck verwendet werden kann:

- Erfolg: 0 ("Wahr/True")

- Fehler: nicht 0 ("Falsch/False")

| Anmerkung
"0" im Kontext eines bedingten Ausdrucks für die Shell bedeutet "Wahr", während "0" im Kontext eines bedingten Ausdrucks für ein C-Programm "Falsch" bedeutet.

| Anmerkung
"`[`" ist das Äquivalent des `test`-Befehls; Argumente bis zum "`]`" werden als bedingter Ausdruck gewertet.

Grundlegende Ausdrucksformen für bedingte Ausdrücke, die Sie sich einprägen sollten:

- "`befehl && bei_erfolg_auch_diesen_befehl_ausführen || true`"

- "`befehl || falls_kein_erfolg_auch_diesen_befehl_ausführen || true`"

- ein mehrzeiliger Skriptschnipsel wie dieser:

    if [ conditional_expression ]; then
     if_success_run_this_command
    else
     if_not_success_run_this_command
    fi

Hierbei ist das "`|| true`" am Ende erforderlich, um sicherzustellen, dass das Shell-Skript sich bei dieser Zeile nicht fälschlicherweise beendet, wenn die Shell mit der "`-e`"-Option aufgerufen wird.

Tabelle 12.5. Liste von Dateivergleichsoperatoren in bedingten Ausdrücken

Gleichung | Wahr wenn …
--- | ---
`-e datei` | datei existiert
`-d datei` | datei existiert und ein Verzeichnis ist
`-f datei` | datei existiert und eine reguläre Datei ist
`-w datei` | datei existiert und schreibbar ist
`-x datei` | datei existiert und ausführbar ist
`datei1 -nt datei2` | datei1 neuer als datei2 ist (Änderungszeitpunkt)
`datei1 -ot datei2` | datei1 älter als datei2 ist (Änderungszeitpunkt)
`datei1 -ef datei2` | datei1 und datei2 die gleiche Device- und Inode-Nummer haben

Tabelle 12.6. Liste von String-Vergleichsoperatoren im bedingten Ausdruck

Gleichung | Wahr wenn …
--- | ---
`-z str` | die Länge von str gleich Null ist
`-n str` | die Länge von str nicht Null ist
`str1 = str2` | str1 und str2 gleich sind
`str1 != str2` | str1 und str2 ungleich sind
`str1 < str2` | str1 in der Sortierung vor str2 erscheint (Locale-abhängig)
`str1 > str2` | str1 in der Sortierung hinter str2 erscheint (Locale-abhängig)

Arithmetische Ganzzahlvergleicher in bedingten Ausdrücken sind "`-eq`", "`-ne`", "`-lt`", "`-le`", "`-gt`" und "`-ge`".

### 12.1.4. Shell-Schleifen

Es gibt mehrere Ausdrucksweisen für Schleifen, die in POSIX-Shells genutzt werden können:

- "`for x in foo1 foo2 … ; do befehl ; done`" führt Schleifen aus, indem Einträge aus der Liste "`foo1 foo2 …`" der Variable "`x`" zugewiesen werden und dann "`befehl`" ausgeführt wird.

- "`while bedingung ; do befehl ; done`" wiederholt "`befehl`", solange "`bedingung`" wahr ist.

- "`until bedingung ; do befehl ; done`" wiederholt "`befehl`", solange "`bedingung`" nicht wahr ist.

- "`break`" ermöglicht, die Bearbeitung der Schleife zu beenden.

- "`continue`" ermöglicht, den nächsten Umlauf der Schleife fortzusetzen.

| Tipp
Die der C-Sprache ähnliche nummerische Wiederholung (Iteration) kann realisiert werden, indem seq(1) für die Erzeugung der "`foo1 foo2 …`"-Liste genutzt wird.

| Tipp
Lesen Sie auch Abschnitt 9.4.9, „Einen Befehl wiederholt mit einer Schleife über verschiedene Dateien ausführen“.

### 12.1.5. Shell-Umgebungsvariablen

Einige populäre Umgebungsvariablen für den normalen Shell-Befehlsprompt könnten in der Ausführungsumgebung Ihres Skriptes nicht verfügbar ein.

- Statt "`$USER`" nutzen Sie besser "`$(id -un)`"

- Statt "`$UID`" nutzen Sie besser "`$(id -u)`"

- Statt "`$HOME`" nutzen Sie besser "`$(getent passwd "$(id -u)"|cut -d ":" -f 6)`" (dies funktioniert auch für Abschnitt 4.5.2, „Modernes zentralisiertes Systemmanagement“).

### 12.1.6. Befehlsabfolge auf der Shell

Die Shell verarbeitet ein Skript im Prinzip in der folgenden Abfolge:

- Die Shell liest eine Zeile.

- Die Shell gruppiert Teile der Zeile zu zusammengehörigen Ausdrücken (Token) zusammen, wenn diese sich innerhalb von `"…"` oder `'…'` befinden.

- Die Shell splittet andere Teile der Zeile in einzelne Ausdrücke (Token) auf, wenn diese wie folgt von einander getrennt sind:

  - Whitespace-Zeichen: `Leerzeichen Tabulator newline`

  - Metazeichen: `< > | ; & ( )`

- Die Shell prüft jeden Ausdruck auf Schlüsselworte (wenn nicht innerhalb von `"…"` oder `'…'`), um deren Verhalten anzupassen.

  - Schlüsselwörter sind: `if then elif else fi for in while unless do done case esac`

- Die Shell expandiert Alias-Befehle (wenn nicht innerhalb von `"…"` oder `'…'`).

- Die Shell expandiert eine Tilde (wenn nicht innerhalb von `"…"` oder `'…'`):

  - "`~`" → Heimatverzeichnis des aktuellen Benutzers

  - "`~benutzer`" → Heimatverzeichnis von `benutzer`

- Die Shell expandiert Parameter in deren Wert (wenn nicht innerhalb von `'…'`):

  - Parameter: "`$PARAMETER`" oder "`${PARAMETER}`"

- Die Shell expandiert Befehlsersetzungen / command substitutions (wenn nicht innerhalb von `'…'`):

  - "`$( befehl )`" → die Ausgabe von "`befehl`"

  - "`` befehl ``" → die Ausgabe von "`befehl`"

- Die Shell expandiert Pfadnamenmuster in die passenden Dateinamen (wenn nicht innerhalb von `"…"` oder `'…'`):

  - `*` → jegliche Zeichen (eins oder mehrere)

  - `?` → irgendein (nur ein) Zeichen

  - `[…]` → jegliche Zeichen von denen in "`…`"

- Die Shell sucht befehl in folgenden Definitionen und führt ihn aus:

  - Funktions-Definition

  - Builtin (integrierter Befehl)

  - ausführbare Datei in "`$PATH`"

- Die Shell geht zur nächsten Zeile und wiederholt diesen kompletten Ablauf vom Anfang.

Einfache Anführungszeichen innerhalb von doppelten Anführungszeichen haben keine Wirkung.

Das Ausführen von "`set -x`" in der Shell oder das Aufrufen einer Shell mit der Option "`-x`" veranlasst die Shell, alle ausgeführten Befehle auch auf dem Bildschirm auszugeben. Dies ist sehr nützlich zur Fehlersuche.

### 12.1.7. Hilfsprogramme für Shell-Skripte

Um Ihr Shell-Programm innerhalb des Debian-Systems möglichst weit portierbar zu machen, ist es eine gute Idee, die zu nutzenden Hilfsprogramme auf diejenigen einzuschränken, welche durch die essential-Pakete bereitgestellt werden:

- "`aptitude search ~E`" listet alle essential-Pakete auf;

- "`dpkg -L paketname |grep '/man/man.*/'`" listet Handbuchseiten (manpages) derjenigen Befehle auf, die von dem Paket `paketname` bereitgestellt werden.

Tabelle 12.7. Liste der Pakete, die kleine Hilfsprogramme für Shell-Skripte enthalten

Paket | Popcon | Größe | Beschreibung
--- | --- | --- | ---
`dash` | V:928, I:998 | 207 | kleine und schnelle, fast POSIX-kompatible Shell für `sh`
`coreutils` | V:911, I:1000 | 17994 | Grundlegende GNU-Werkzeuge
`grep` | V:783, I:1000 | 1297 | GNU `grep`, `egrep` und `fgrep`
`sed` | V:753, I:1000 | 987 | GNU `sed`
`mawk` | V:484, I:998 | 295 | kleine und schnelle Alternative zu `awk`
`debianutils` | V:935, I:996 | 225 | verschiedene Hilfsprogramme speziell für Debian
`bsdutils` | V:443, I:999 | 334 | grundlegende Kommandos aus 4.4BSD-Lite
`bsdextrautils` | V:753, I:859 | 378 | weitere Kommandos aus 4.4BSD-Lite
`moreutils` | V:17, I:39 | 232 | zusätzliche Unix-Hilfsprogramme

| Tipp
Obwohl `moreutils` außerhalb von Debian unter Umständen nicht verfügbar ist, bietet es interessante kleine Programme. Das erwähnenswerteste ist sponge(8); es ist sehr nützlich, wenn Sie eine Originaldatei überschreiben möchten.

Beispiele finden Sie in Abschnitt 1.6, „Unix-ähnliche Textverarbeitung“.

## 12.2. Skriptverarbeitung in Interpreter-Sprachen

Tabelle 12.8. Liste von Interpreter-betreffenden Paketen

Paket | Popcon | Größe | Dokumentation
--- | --- | --- | ---
`dash` | V:928, I:998 | 207 | sh: kleine und schnelle POSIX-kompatible Shell für `sh`
`bash` | V:888, I:999 | 7276 | sh: "`info bash`" aus dem `bash-doc`-Paket
`mawk` | V:484, I:998 | 295 | AWK: kleine und schnelle Alternative zu `awk`
`gawk` | V:252, I:303 | 3289 | AWK: "`info gawk`" aus dem `gawk-doc`-Paket
`perl` | V:668, I:992 | 838 | Perl: perl(1) bzw. die HTML-Seiten aus dem `perl-doc`- oder `perl-doc-html`-Paket
`libterm-readline-gnu-perl` | V:2, I:28 | 439 | Perl-Erweiterung für die GNU ReadLine/History-Bibliothek: perlsh(1)
`libreply-perl` | V:0.00, I:0.09 | 171 | REPL für Perl: reply(1)
`libdevel-repl-perl` | V:0.03, I:0.54 | 237 | REPL für Perl: re.pl(1)
`python3` | V:721, I:973 | 81 | Python: python3(1) bzw. die HTML-Seiten aus dem `python3-doc`-Paket
`tcl` | V:23, I:178 | 20 | Tcl: tcl(3) und detaillierte Handbuchseiten aus dem `tcl-doc`-Paket
`tk` | V:18, I:172 | 20 | Tk: tk(3) und detaillierte Handbuchseiten aus dem `tk-doc`-Paket
`ruby` | V:71, I:160 | 32 | Ruby: ruby(1), erb(1), irb(1), rdoc(1), ri(1)

Wenn Sie auf einem Debian-System eine Aufgabe automatisieren möchten, sollten Sie es zunächst mit einer Interpreter-Sprache versuchen. Eine Richtschnur für die Auswahl der passenden Sprache ist:

- Verwenden Sie `dash`, wenn die Aufgabe einfach ist und Konsolen-Befehle mit einem Shell-Programm kombiniert werden.

- Verwenden Sie `python3`, wenn es keine einfache Aufgabe ist und Sie alles von Grund auf neu schreiben.

- Verwenden Sie `perl`, `tcl`, `ruby`, ... falls bereits vorhandener Code in einer dieser Sprachen existiert, der übernommen werden muss, um die Aufgabe erledigen zu können.

Falls der resultierende Code zu langsam ist, können Sie den kritischen Teil zwecks Ausführung in einer kompilierten Sprache neu schreiben und diesen von der Interpreter-Sprache aus aufrufen.

### 12.2.1. Fehlersuche im Code für Interpreter-Sprachen

Die meisten Interpreter bieten eine grundlegende Syntaxprüfung und Funktionalitäten zur Code-Nachverfolgung.

- “dash -n script.sh” - Syntaxprüfung eines Shell-Skripts

- “dash -x script.sh” - Nachverfolgung (Trace) eines Shell-Skripts

- “python -m py_compile script.py” - Syntaxprüfung eines Python-Skripts

- “python -mtrace --trace script.py” - Nachverfolgung (Trace) eines Python-Skripts

- “perl -I ../libpath -c script.pl” - Syntaxprüfung eines Perl-Skripts

- “perl -d:Trace script.pl” - Nachverfolgung (Trace) eines Perl-Skripts

Um Code für `dash` zu testen, versuchen Sie Abschnitt 9.1.4, „Readline-Wrapper“, um eine `bash`-ähnliche interaktive Umgebung zu erhalten.

Um Code für `perl` zu testen, versuchen Sie eine REPL-Umgebung für Perl; sie bietet Ihnen eine Python-ähnliche REPL (=READ + EVAL + PRINT + LOOP)-Umgebung für Perl.

### 12.2.2. Grafisches GUI-Programm und Shell-Skripte

Ein Shell-Skript kann aufgewertet werden, um ein attraktives GUI-Programm zu erzeugen. Der Trick ist, eines der sogenannten Dialog-Programme zu verwenden, statt der stumpfen Interaktion über `echo`- und `read`-Befehle.

Tabelle 12.9. Liste von Dialog-Programmen

Paket | Popcon | Größe | Beschreibung
--- | --- | --- | ---
`x11-utils` | V:225, I:555 | 651 | xmessage(1): eine Nachricht oder Abfrage in einem Fenster anzeigen (X)
`whiptail` | V:307, I:997 | 61 | nutzerfreundliche Dialogboxen von Shell-Skripten anzeigen (newt)
`dialog` | V:8, I:80 | 520 | nutzerfreundliche Dialogboxen von Shell-Skripten anzeigen (ncurses)
`zenity` | V:77, I:342 | 193 | grafische Dialogboxen von Shell-Skripten anzeigen (GTK)
`ssft` | V:0.01, I:0.15 | 75 | Werkzeug für Shell-Skript-Oberflächen (Aufrufprogramm für zenity, kdialog und dialog mit gettext)
`gettext` | V:51, I:219 | 20468 | "`/usr/bin/gettext.sh`": Meldungen übersetzen

Hier ein Beispiel für ein GUI-Programm, um zu demonstrieren, wie einfach es sein kann mit nur einem Shell-Skript.

Dieses Skript nutzt `zenity`, um eine Datei auszuwählen (Standardvorwahl ist `/etc/motd`) und sie anzuzeigen.

Ein grafischer Starter für dieses Skript kann erstellt werden gemäß Abschnitt 9.4.10, „Ein Programm aus der grafischen Oberfläche heraus starten“.

    #!/bin/sh -e
    # Copyright (C) 2021 Osamu Aoki <osamu@debian.org>, Public Domain
    # vim:set sw=2 sts=2 et:
    DATA_FILE=$(zenity --file-selection --filename="/etc/motd" --title="Select a file to check") || \
      ( echo "E: File selection error" >&2 ; exit 1 )
    # Check size of archive
    if ( file -ib "$DATA_FILE" | grep -qe '^text/' ) ; then
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="$(head -n 20 "$DATA_FILE")"
    else
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="The data is MIME=$(file -ib "$DATA_FILE")"
    fi

Dieser Ansatz eines grafischen Programms mit einem Shell-Skript ist nur für einfache Auswahlen sinnvoll. Wenn Sie komplexere Programme schreiben, sollten Sie die Nutzung von geeigneten Plattformen in Erwägung ziehen.

### 12.2.3. Eigene Aktionen im Dateimanager

Grafische Dateimanager können erweitert werden, um einige populäre Aktionen für ausgewählte Dateien ausführen zu können; dazu müssen eventuell zusätzliche Erweiterunspakete installiert werden. Auch können spezielle eigene Aktionen ausführt werden, indem Sie selbst erstellte Skripte hinzufügen.

- Für GNOME lesen Sie dazu NautilusScriptsHowto.

- Für KDE finden Sie weitere Details in Creating Dolphin Service Menus.

- Für Xfce sollten Sie Thunar - Custom Actions und https://help.ubuntu.com/community/ThunarCustomActions besuchen.

- Für LXDE schauen Sie unter Custom Actions.

### 12.2.4. Verrücktes bei kurzen Perl-Skripten

Um Prozessdaten zu verarbeiten, muss `sh` Unterprozesse generieren, um `cut`, `grep`, `sed` usw. aufrufen zu können; und es ist langsam. Auf der anderen Seite enthält `perl` interne Funktionalitäten zur Verarbeitung von Prozessdaten, und es ist schnell. Daher nutzen viele Wartungsskripte in Debian `perl`.

Denken wir an folgendes einzeilige AWK-Skript und sein Äquivalent in Perl:

    awk '($2=="1957") { print $3 }' |

Es ist äquivalent zu jeder der folgenden Zeilen:

    perl -ne '@f=split; if ($f[1] eq "1957") { print "$f[2]\n"}' |

    perl -ne 'if ((@f=split)[1] eq "1957") { print "$f[2]\n"}' |

    perl -ne '@f=split; print $f[2] if ( $f[1]==1957 )' |

    perl -lane 'print $F[2] if $F[1] eq "1957"' |

    perl -lane 'print$F[2]if$F[1]eq+1957' |

Das letzte ist eine Knobelaufgabe. Es nutzt die Vorteile folgender Perl-Funktionen:

- Der Whitespace ist optional.

- Es existiert eine automatische Konvertierung von Zahlen zu Zeichenketten.

- Perl's Befehlsausführungstricks über Befehlszeilen-Optionen: perlrun(1)

- Perl's spezielle Variablen: perlvar(1)

Diese Flexibilität ist die Stärke von Perl. Gleichzeitig erlaubt sie aber auch die Erstellung von kryptischem und verwinkeltem Code. Seien Sie vorsichtig.

## 12.3. Programmieren in kompilierten Sprachen

Tabelle 12.10. Liste von Compiler-betreffenden Paketen

Paket | Popcon | Größe | Beschreibung
--- | --- | --- | ---
`gcc` | V:157, I:565 | 36 | GNU-C-Compiler
`libc6-dev` | V:268, I:584 | 12676 | GNU-C-Bibliothek: Entwicklungsbibliotheken und Header-Dateien
`g++` | V:59, I:531 | 13 | GNU-C++-Compiler
`libstdc++-15-dev` | V:5, I:23 | 25228 | GNU Standard-C++-Bibliothek Version 3 (Entwicklungsdateien)
`cpp` | V:338, I:721 | 18 | GNU-C-Preprozessor
`gettext` | V:51, I:219 | 20468 | GNU-Werkzeuge für die Internationalisierung
`glade` | V:0.2, I:2.8 | 1613 | Builder für die GTK-Bedienoberfläche
`valac` | V:0.3, I:3.0 | 533 | C#-ähnliche Sprache für das GObject-System
`flex` | V:6, I:68 | 1247 | LEX-kompatibler schneller lexikalischer Analysegenerator
`bison` | V:7, I:72 | 3122 | YACC-kompatibler Parser-Generator
`susv2` | I:0.03 | 16 | die "Single UNIX Specifications v2"
`susv3` | I:0.05 | 16 | die "Single UNIX Specifications v3"
`susv4` | I:0.04 | 16 | die "Single UNIX Specifications v4"
`golang` | I:21 | 12 | Compiler für die Programmiersprache Go
`rustc` | V:5, I:19 | 13061 | Rust System-Programmiersprache
`gfortran` | V:5, I:50 | 15 | GNU-Fortran-95-Compiler
`fpc` | I:2.3 | 101 | Free Pascal

Hierbei sind flex (siehe Abschnitt 12.3.3, „Flex - ein besseres Lex“) und bison (siehe Abschnitt 12.3.4, „Bison - ein besseres Yacc“) mit aufgeführt, um zu zeigen, wie Compiler-ähnliche Programme in der Sprache C erstellt werden können, indem höherwertige Beschreibungssprachen in C kompiliert werden.

### 12.3.1. C

Sie können wie folgt eine korrekte Umgebung zum Kompilieren von in der C-Programmiersprache geschriebenen Programmen einrichten:

    # apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential

Das Paket `libc6-dev` (d.h. die GNU-C-Bibliothek) bietet als C-Standard-Bibliothek eine Sammlung von Header-Dateien und Bibliotheksroutinen, die von der C-Sprache genutzt werden.

Referenzen für C finden Sie über:

- "`info libc`" (Referenz für Funktionen der C-Bibliothek)

- gcc(1) und "`info gcc`"

- jeglicher_funktionsname_aus_der_c_bibliothek(3)

- Kernighan & Ritchie, "The C Programming Language", 2. Ausgabe (Prentice Hall)

### 12.3.2. Ein einfaches C-Programm (gcc)

Hier ein einfaches Beispiel zum Kompilieren von "`example.c`" mit der Bibliothek "`libm`" in eine ausführbare Datei "`run_example`":

    $ cat > example.c << EOF
    #include <stdio.h>
    #include <math.h>
    #include <string.h>

    int main(int argc, char **argv, char **envp){
            double x;
            char y[11];
            x=sqrt(argc+7.5);
            strncpy(y, argv[0], 10); /* prevent buffer overflow */
            y[10] = '\0'; /* fill to make sure string ends with '\0' */
            printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]);
            return 0;
    }
    EOF
    $ gcc -Wall -g -o run_example example.c -lm
    $ ./run_example
            1, 2.915, ./run_exam,     (null)
    $ ./run_example 1234567890qwerty
            2, 3.082, ./run_exam, 1234567890qwerty

Hierbei wird "`-lm`" benötigt, um die Bibliothek "`/usr/lib/libm.so`" aus dem `libc6`-Paket für sqrt(3) zu verlinken. Die eigentliche Bibliothek liegt in "`/lib/`" und hat den Dateinamen "`libm.so.6`", was ein symbolischer Link auf "`libm-2.7.so`" ist.

Schauen Sie sich den letzten Parameter im ausgegebenen Text an. Dort werden mehr als 10 Zeichen ausgegeben, obwohl "`%10s`" angegeben wurde.

Die Verwendung von Funktionen, die Zeiger auf Speicherbereiche ohne Bereichsüberprüfung nutzen (wie sprintf(3) und strcpy(3)), wird missbilligt, um das Ausnutzen von Pufferüberläufen zu verhindern, die obige Überlaufeffekte in Gang bringen. Verwenden Sie stattdessen snprintf(3) und strncpy(3).

### 12.3.3. Flex - ein besseres Lex

Flex ist ein Lex-kompatibler schneller lexikalischer Analysegenerator.

Eine Einführung zu flex(1) finden Sie in "`info flex`".

Sie finden viele einfache Beispiele unter "`/usr/share/doc/flex/examples/`". [7]

### 12.3.4. Bison - ein besseres Yacc

Einige Pakete stellen Yacc-kompatible LR-Parser- oder LALR-Parser-Generatoren in Debian bereit:

Tabelle 12.11. Liste Yacc-kompatibler LALR-Parser-Generatoren

Paket | Popcon | Größe | Beschreibung
--- | --- | --- | ---
`bison` | V:7, I:72 | 3122 | GNU LALR-Parser-Generator
`byacc` | V:0.2, I:3.1 | 263 | Berkeley LALR-Parser-Generator
`btyacc` | V:0.01, I:0.06 | 247 | rückverfolgender Parser-Generator basierend auf `byacc`

Eine Einführung zu bison(1) finden Sie in "`info bison`".

Sie müssen Ihre eigenen "`main()`"- und "`yyerror()`"-Funktionen bereitstellen. "`main()`" ruft "`yyparse()`" auf, das wiederum "`yylex()`" aufruft, was gewöhnlich von FleX erzeugt wird.

Hier ein Beispiel für die Erstellung eines einfachen terminal-basierten Taschenrechner-Programms.

Lassen Sie uns `example.y` erstellen:

    /* calculator source for bison */
    %{
    #include <stdio.h>
    extern int yylex(void);
    extern int yyerror(char *);
    %}

    /* declare tokens */
    %token NUMBER
    %token OP_ADD OP_SUB OP_MUL OP_RGT OP_LFT OP_EQU

    %%
    calc:
     | calc exp OP_EQU    { printf("Y: RESULT = %d\n", $2); }
     ;

    exp: factor
     | exp OP_ADD factor  { $$ = $1 + $3; }
     | exp OP_SUB factor  { $$ = $1 - $3; }
     ;

    factor: term
     | factor OP_MUL term { $$ = $1 * $3; }
     ;

    term: NUMBER
     | OP_LFT exp OP_RGT  { $$ = $2; }
      ;
    %%

    int main(int argc, char **argv)
    {
      yyparse();
    }

    int yyerror(char *s)
    {
      fprintf(stderr, "error: '%s'\n", s);
    }

Und dann `example.l`:

    /* calculator source for flex */
    %{
    #include "example.tab.h"
    %}

    %%
    [0-9]+ { printf("L: NUMBER = %s\n", yytext); yylval = atoi(yytext); return NUMBER; }
    "+"    { printf("L: OP_ADD\n"); return OP_ADD; }
    "-"    { printf("L: OP_SUB\n"); return OP_SUB; }
    "*"    { printf("L: OP_MUL\n"); return OP_MUL; }
    "("    { printf("L: OP_LFT\n"); return OP_LFT; }
    ")"    { printf("L: OP_RGT\n"); return OP_RGT; }
    "="    { printf("L: OP_EQU\n"); return OP_EQU; }
    "exit" { printf("L: exit\n");   return YYEOF; } /* YYEOF = 0 */
    .      { /* ignore all other */ }
    %%

Führen Sie dann auf der Shell folgendes aus:

    $ bison -d example.y
    $ flex example.l
    $ gcc -lfl example.tab.c lex.yy.c -o example
    $ ./example
    1 + 2 * ( 3 + 1 ) =
    L: NUMBER = 1
    L: OP_ADD
    L: NUMBER = 2
    L: OP_MUL
    L: OP_LFT
    L: NUMBER = 3
    L: OP_ADD
    L: NUMBER = 1
    L: OP_RGT
    L: OP_EQU
    Y: RESULT = 9

    exit
    L: exit

## 12.4. Werkzeuge zur statischen Code-Analyse

Lint-ähnliche Werkzeuge können bei der automatisierten statischen Code-Analyse helfen.

Werkzeuge wie Indent können Menschen bei Code-Überprüfungen helfen, indem Quellcode einheitlich formatiert wird.

Ctags-ähnliche Werkzeuge können Menschen bei Code-Überprüfungen helfen, indem eine Index- (oder Tag-)Datei mit im Quellcode gefundenen Namen erzeugt wird.

| Tipp

Konfigurieren Sie Ihren Lieblingseditor (z.B. `emacs` oder `vim`), so dass er asynchrone Lint-Engine-Plugins nutzt und Sie so beim Schreiben von Code unterstützt. Diese Plugins werden sehr mächtig, indem Sie die Vorteile des Language-Server-Protokolls nutzen. Da sie sich sehr schnell ändern, könnte es eine gute Option sein, die Software von Upstream zu verwenden statt des entsprechenden Debian-Pakets.

Tabelle 12.12. Liste von Werkzeugen für die statische Code-Analyse

Paket | Popcon | Größe | Beschreibung
--- | --- | --- | ---
`vim-ale` | I:0.78 | 2833 | Asynchrone Lint-Engine für Vim 8 und NeoVim
`vim-syntastic` | I:2.0 | 1379 | Syntaxprüfungen für Vim
`elpa-flycheck` | V:0.1, I:1.6 | 815 | moderne on-the-fly Syntaxprüfung für Emacs
`elpa-relint` | V:0.01, I:0.05 | 150 | Fehlersuche mittels Regexp für Emacs-Lisp-Dateien
`cppcheck-gui` | V:0.11, I:0.99 | 7722 | Werkzeug für die statische C/C++-Code-Analyse (GUI)
`shellcheck` | V:3, I:16 | 22860 | Lint-Werkzeug für Shell-Skripte
`pyflakes3` | V:1, I:14 | 20 | passive Prüfung von Python3-Programmen
`pylint` | V:3, I:20 | 2089 | Statisches Prüfprogramm für Python-Code
`perl` | V:668, I:992 | 838 | Interpreter mit internem statischen Code-Prüfmechanismus: `B::Lint`(3perl)
`rubocop` | V:0.07, I:1.00 | 4157 | statischer Code-Analyser für Ruby
`clang-tidy` | V:2, I:11 | 21 | clang-basiertes C++-Linter-Werkzeug
`splint` | V:0.06, I:0.94 | 2325 | Werkzeug zur statischen Überprüfung von C-Programmen auf Programmfehler
`flawfinder` | V:0.07, I:0.44 | 205 | Werkzeug zur Durchsuchung von Quellcode auf Sicherheitsschwächen
`black` | V:3, I:16 | 10057 | kompromissloser Python-Code-Formatierer
`perltidy` | V:0.4, I:3.0 | 3086 | Einrücker und Neuformatierer für Perl-Skripte
`indent` | V:0.3, I:5.1 | 438 | Code-Formatierer für C
`astyle` | V:0.2, I:2.5 | 770 | Quelltextformatierer für C, C++, Objective-C, C# und Java
`bcpp` | V:0.02, I:0.25 | 114 | C(++)-Code schön machen
`xmlindent` | V:0.08, I:0.77 | 52 | Neuformatierung von XML-Datenströmen
`global` | V:0.2, I:1.6 | 1923 | Werkzeuge zum Suchen und Browsen in Quelltext
`exuberant-ctags` | V:2, I:13 | 341 | Erzeugen von Indexdateien aus Quelltextdefinitionen
`universal-ctags` | V:1, I:12 | 4238 | Erzeugen von Indexdateien aus Quelltextdefinitionen

## 12.5. Fehlersuche (Debugging)

Debugging ist ein wichtiger Teil der Programmieraktivitäten. Das Wissen darüber, wie man in Programmen einen Fehler sucht, macht Sie zu einem guten Debian-Nutzer, der aussagekräftige Fehlerberichte erstellen kann.

Tabelle 12.13. Liste von Debugging-Paketen

Paket | Popcon | Größe | Dokumentation
--- | --- | --- | ---
`gdb` | V:87, I:159 | 12456 | "`info gdb`" aus dem `gdb-doc`-Paket
`ddd` | V:0.3, I:5.2 | 4210 | "`info ddd`" aus dem `ddd-doc`-Paket

### 12.5.1. Grundlegende Ausführung von gdb

Das primäre Programm zur Fehlersuche (Debugger) im Debian-System ist gdb(1), welches Ihnen erlaubt, ein Programm zu inspizieren, während es läuft.

Wir installieren `gdb` und zugehörige Programme wie folgt:

    # apt-get install gdb gdb-doc build-essential devscripts

Gute Einführungen zu `gdb` finden Sie unter:

- “`info gdb`”

- “Debugging with GDB” in `/usr/share/doc/gdb-doc/html/gdb/index.html`

- “Einführungen im Netz”

Hier ein einfaches Beispiel zur Verwendung von gdb(1) bei einem Programm namens "`program`", kompiliert mit der Option "`-g`", um Debugging-Informationen auszugeben.

    $ gdb program
    (gdb) b 1                # set break point at line 1
    (gdb) run args           # run program with args
    (gdb) next               # next line
    ...
    (gdb) step               # step forward
    ...
    (gdb) p parm             # print parm
    ...
    (gdb) p parm=12          # set value to 12
    ...
    (gdb) quit

| Tipp
Viele gdb(1)-Befehle können abgekürzt werden. Vervollständigungen funktionieren wie in der Shell mit der Tabulator-Taste.

### 12.5.2. Fehlersuche (Debugging) in einem Debian-Paket

Da installierte Binärdateien auf einem Debian-System normalerweise nicht unnötig aufgebläht sein sollten, werden Debugging-Symbole in normalen Paketen meistens entfernt. Um bei solchen Paketen Debugging mit gdb(1) durchführen zu können, müssen `*-dbgsym`-Pakete installiert werden (z.B. `coreutils-dbgsym` für das `coreutils`-Paket). Die Quellpakete erzeugen diese `*-dbgsym`-Debug-Pakete automatisch mit den normalen Binärpaketen und sie werden in dem separaten Archiv debian-debug abgelegt. Bitte lesen Sie die entsprechenden Artikel im Debian Wiki, wenn Sie weitere Informationen benötigen.

Falls ein Paket, bei dem eine Fehlersuche durchgeführt werden soll, kein `*-dbgsym`-Paket anbietet, müssen Sie es händisch neu bauen und dann installieren, wie hier:

    $ mkdir /path/new ; cd /path/new
    $ sudo apt-get update
    $ sudo apt-get dist-upgrade
    $ sudo apt-get install fakeroot devscripts build-essential
    $ apt-get source package_name
    $ cd package_name*
    $ sudo apt-get build-dep ./

Beheben Sie die Fehler, falls erforderlich.

Erhöhen Sie die Paketversion auf eine Versionsnummer, die nicht mit offiziellen Debian-Versionen kollidiert (Sie können z.B. ein "`+debug1`" anhängen, wenn Sie eine existierende Paketversion neu kompilieren, oder Sie hängen "`~pre1`" an, wenn Sie eine noch nicht veröffentlichte Paketversion selbst kompilieren). Verwenden Sie dazu:

    $ dch -i

Kompilieren und installieren Sie ein Paket mit Debugging-Symbolen wie folgt:

    $ export DEB_BUILD_OPTIONS="nostrip noopt"
    $ debuild
    $ cd ..
    $ sudo debi package_name*.changes

Sie müssen die Build-Skripte des Pakets überprüfen und sicherstellen, dass "`CFLAGS=-g -Wall`" zum Kompilieren der Binärdateien verwendet wird.

### 12.5.3. Gewinnen von Backtrace-Informationen

Wenn Sie einen Programmabsturz erlitten haben, ist es eine gute Idee, einen Fehlerbericht einzureichen und an diesen zusätzliche Backtrace-Informationen (Daten zur Rückverfolgung von Vorgängen in Programmen zwecks Fehleranalyse) anzuhängen, die Sie mittels Kopieren-und-Einfügen erhalten.

Solche Backtrace-Informationen lassen sich mittels gdb(1) über einen der folgenden Ansätze gewinnen:

- der Ansatz "Absturz in GDB":

  - ein Programm über GDB starten

  - einen Absturz des Programms herbeiführen

  - "`bt`" am GDB-Prompt eingeben

- der Ansatz "Zunächst den Absturz herbeiführen":

  - Aktualisieren der Datei “/etc/security/limits.conf”, so dass sie folgendes enthält:

        * soft core unlimited

  - Eingabe von "`ulimit -c unlimited`" in der Shell

  - Aufruf des Programms aus dieser Shell

  - einen Absturz des Programms herbeiführen, um eine Dump-Datei zu erzeugen

  - Laden der Dump-Datei in GDB mit "`gdb gdb ./program_binary core`"

  - "`bt`" am GDB-Prompt eingeben

Im Falle einer Endlosschleife oder bei eingefrorener Tastatur können Sie einen Absturz des Programms mit `Strg-\` oder `Strg-C` herbeiführen, oder indem Sie “`kill -ABRT PID`” ausführen (Näheres dazu in Abschnitt 9.4.12, „Einen Prozess beenden (kill)“).

| Tipp

Oft stellt man fest, dass in den Backtrace-Informationen eine oder mehrere der ersten Zeilen "`malloc()`" oder "`g_malloc()`" enthalten. Wenn dies passiert, besteht eine hohe Wahrscheinlichkeit, dass Ihr Backtrace nicht sehr nützlich sein wird. Der einfachste Weg nützliche Informationen zu bekommen ist, die Umgebungsvariable "`$MALLOC_CHECK_`" auf einen Wert von 2 zu setzen (Näheres in malloc(3)). Sie können dies wie folgt erledigen, während `gdb` läuft:

     $ MALLOC_CHECK_=2 gdb hello

### 12.5.4. Erweiterte gdb-Befehle

Tabelle 12.14. Liste erweiterter gdb-Befehle

Befehl | Beschreibung
--- | ---
`(gdb) thread apply all bt` | Backtrace für alle Threads eines Multi-Thread-Programms auslesen
`(gdb) bt full` | Parameter auslesen, die auf dem Aufruf-Stack der Funktionsaufrufe aufgelaufen sind
`(gdb) thread apply all bt full` | Backtrace und Parameter als Kombination der vorangegangenen Optionen auslesen
`(gdb) thread apply all bt full 10` | Backtrace und Parameter für die ersten 10 Aufrufe auslesen, um irrelevante Ausgaben abzuschneiden
`(gdb) set logging on` | Protokoll der Ausgabe von `gdb` in eine Datei schreiben (Standard ist "`gdb.txt`")

### 12.5.5. Überprüfen der Abhängigkeiten von Bibliotheken

Verwenden Sie ldd(1) wie hier, um zu ermitteln, von welchen Bibliotheken ein Programm abhängt:

    $ ldd /usr/bin/ls
            librt.so.1 => /lib/librt.so.1 (0x4001e000)
            libc.so.6 => /lib/libc.so.6 (0x40030000)
            libpthread.so.0 => /lib/libpthread.so.0 (0x40153000)
            /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Damit ls(1) in einer "chroot"-Umgebung funktioniert, müssen die obigen Bibliotheken in der "chroot"-Umgebung vorhanden sein.

Lesen Sie dazu Abschnitt 9.4.6, „Programmaktivitäten verfolgen“.

### 12.5.6. Werkzeuge zur dynamischen Aufrufverfolgung

Es gibt verschiedene Werkzeuge zur dynamischen Aufrufverfolgung in Debian. Schauen Sie in Abschnitt 9.4, „Überwachen, Steuern und Starten von Programmaktivitäten“.

### 12.5.7. Fehleranalyse bei X-Fehlern

Wenn ein GNOME-Programm `preview1` einen X-Fehler empfangen hat, sollten Sie eine Meldung wie diese sehen:

    The program 'preview1' received an X Window System error.

Sollte dies der Fall sein, können Sie versuchen, das Programm mit der Option "`--sync`" zu starten und einen Haltepunkt für die Funktion "`gdk_x_error`" zu setzen, um einen Backtrace zu bekommen.

### 12.5.8. Werkzeuge zur Erkennung von Speicherlecks

Es gibt verschiedene Werkzeuge zur Erkennung von Speicherlecks in Debian:

Tabelle 12.15. Liste von Werkzeugen zur Erkennung von Speicherlecks

Paket | Popcon | Größe | Beschreibung
--- | --- | --- | ---
`libc6-dev` | V:268, I:584 | 12676 | mtrace(1): malloc-Debugging-Funktionalität in glibc
`valgrind` | V:5, I:33 | 87847 | Speicher-Debugging- und Analyse-Programm
`electric-fence` | V:0.2, I:2.4 | 69 | malloc(3)-Debugging-Programm
`libdmalloc5` | V:0.01, I:0.66 | 373 | Bibliothek zur Fehlersuche bei Speicherzuweisungen
`duma` | V:0.01, I:0.06 | 297 | Bibliothek zur Detektierung von Pufferüber- oder -unterläufen in C- und C++-Programmen
`leaktracer` | I:0.39 | 56 | Werkzeug zur Verfolgung von Speicherlecks in C++-Programmen

### 12.5.9. Disassemblieren von Binärdateien

Sie können Binär-Code wie folgt mit objdump(1) disassemblieren:

    $  objdump -m i386 -b binary -D /usr/lib/grub/x86_64-pc/stage1

| Anmerkung
gdb(1) kann verwendet werden, um Code interaktiv zu disassemblieren.

## 12.6. Bauwerkzeuge

Tabelle 12.16. Liste von Paketen mit Bauwerkzeugen

Paket | Popcon | Größe | Dokumentation
--- | --- | --- | ---
`make` | V:152, I:567 | 1762 | "`info make`" aus dem `make-doc`-Paket
`autoconf` | V:27, I:199 | 2244 | "`info autoconf`" aus dem `autoconf-doc`-Paket
`automake` | V:27, I:199 | 1932 | "`info automake`" aus dem `automake1.10-doc`-Paket
`libtool` | V:23, I:182 | 1245 | "`info libtool`" aus dem `libtool-doc`-Paket
`cmake` | V:19, I:122 | 59735 | cmake(1) - plattformübergreifendes, quelloffenes Make-System
`ninja-build` | V:8, I:53 | 456 | ninja(1) - kleines Bausystem nah am Geiste von Make
`meson` | V:6, I:28 | 4277 | meson(1) - hochproduktives Bausystem, aufbauend auf `ninja`
`xutils-dev` | V:0.5, I:6.9 | 1495 | imake(1), xmkmf(1) usw.

### 12.6.1. Make

Make ist ein Werkzeug, um Gruppen von Programmen zu betreuen. Bei Ausführung des Befehls make(1) liest `make` die Regeldatei "`Makefile`" und aktualisiert ein Ziel (Target), falls sich Dateien, von denen das Makefile abhängt, seit der letzten Modifizierung des Targets verändert haben oder falls das Target nicht existiert. Die Ausführungen dieser Aktualisierungen können zeitgleich erfolgen.

Die Syntax der Regeldatei ist folgende:

    target: [ prerequisites ... ]
     [TAB]  command1
     [TAB]  -command2 # ignore errors
     [TAB]  @command3 # suppress echoing

Hierbei ist "`[TAB]`" ein TAB-Code. Jede Zeile wird nach Ersetzung der Variablen durch die Shell interpretiert. Verwenden Sie "`\`" am Ende einer Zeile, um den Befehl in der nächsten Zeile fortzusetzen. Zur Angabe von Umgebungsvariablen müssen Sie statt "`$`" hier "`$$`" schreiben.

Implizite Regeln für das Target und Voraussetzungen können z.B. wie folgt angegeben werden:

    %.o: %.c header.h

Hier enthält das Target das Zeichen "`%`" (exakt eines davon). Das "`%`" passt auf jeden nicht leeren Teil-String in den eigentlichen Dateinamen des Targets. Auch die Voraussetzungen nutzen auf ähnliche Art ein "`%`", um den Bezug zum Namen des Targets anzuzeigen.

Tabelle 12.17. Liste von automatischen make-Variablen

automatische Variable | Wert
--- | ---
`$@` | Ziel
`$<` | erste Voraussetzung
`$?` | alle neueren Voraussetzungen
`$^` | alle Voraussetzungen
`$*` | "`%`" trifft auf den Stamm im Target-Muster zu

Tabelle 12.18. Liste von make-Variablenexpandierungen

Variablenexpandierung | Beschreibung
--- | ---
`foo1 := bar` | einmalige Expandierung
`foo2 = bar` | rekursive Expandierung
`foo3 += bar` | anhängen

Führen Sie "`make -p -f/dev/null`" aus, um alle internen automatischen Regeln zu sehen.

### 12.6.2. Autotools

Autotools ist eine Sammlung von Programmierwerkzeugen, entwickelt, um dabei zu helfen, Quellcode-Pakete auf viele Unix-artige Systeme portierbar zu machen.

- Autoconf ist ein Werkzeug, das ein "`configure`"-Shell-Skript aus einer "`configure.ac`"-Datei erzeugt.

  - "`configure`" wird dann später verwendet, um aus der Vorlage "`Makefile.in`" die "`Makefile`"-Datei zu generieren.

- Automake erstellt aus einer "`Makefile.am`" eine "`Makefile.in`".

- Libtool ist ein Shell-Skript für die Problematik der Portabilität beim Kompilieren dynamischer Bibliotheken aus Quellcode.

#### 12.6.2.1. Kompilieren und Installieren eines Programms

| Warnung
Überschreiben Sie keine Systemdateien, wenn Sie Ihre selbst kompilierten Programme installieren.

Debian verändert keine Dateien unter "`/usr/local/`" oder "`/opt`". Wenn Sie also ein Programm aus den Quellen kompilieren, sollten Sie es in "`/usr/local/`" installieren, damit es nicht mit Debian kollidiert.

    $ cd src
    $ ./configure --prefix=/usr/local
    $ make # this compiles program
    $ sudo make install # this installs the files in the system

#### 12.6.2.2. Deinstallation eines Programms

Wenn Sie noch den Original-Quellcode haben, dieser autoconf(1)/automake(1) nutzt und Sie noch wissen, wie Sie es konfiguriert haben, verfahren Sie wie folgt, um das Programm zu deinstallieren:

    $ ./configure all-of-the-options-you-gave-it
    $ sudo make uninstall

Wenn Sie sich absolut sicher sind, dass der Installationsprozess Dateien nur unter "`/usr/local/`" abgelegt hat und und es nichts Wichtiges mehr dort gibt, können Sie alternativ auch alles löschen, wie hier:

    # find /usr/local -type f -print0 | xargs -0 rm -f

Falls Sie nicht sicher sind, wo die Dateien installiert sind, sollten Sie einen Blick auf checkinstall(8) aus dem `checkinstall`-Paket werfen, das einen leeren Pfad für die Deinstallation liefert. Es unterstützt jetzt auch die Erzeugung eines Debian-Pakets mit der Option "`-D`".

### 12.6.3. Meson

Das Software-Bausystem hat sich weiterentwickelt:

- Autotools als Aufsatz für Make war seit den 1990'ern der De-Facto-Standard für portable Bauinfrastruktur. Es ist sehr langsam.

- CMake - erstmals veröffentlicht im Jahr 2000 - verbesserte die Geschwindigkeit erheblich, baute allerdings ursprünglich auf dem grundsätzlich langsamen Make auf. (Jetzt kann Ninja als Backend dienen.)

- Ninja - erstmals veröffentlicht in 2012 - trat an, um Make zu ersetzen, um so die Baugeschwindigkeit weiter zu erhöhen, und ist auch darauf angewiesen, dass seine Eingabedateien von einem höherwertigen Bausystem erzeugt werden.

- Meson - erstmals veröffentlicht 2013 - ist das neue populäre und schnelle, hochwertige Bausystem; es verwendet Ninja als Backend.

Sie finden Dokumente hierzu unter "The Meson Build system" and "The Ninja build system".

## 12.7. Web

Einfache interaktive dynamische Webseiten können wie folgt erstellt werden:

- Abfragen werden mittels HTML-Formularen dem Browser-Nutzer präsentiert.

- Das Ausfüllen und Anklicken von Formulareinträgen sendet einen URL-String mit kodierten Parametern vom Browser zum Webserver:

  - "`https://www.foo.dom/cgi-bin/program.pl?WERT1=WERT1&WERT2=WERT2&WERT3=WERT3`"

  - "`https://www.foo.dom/cgi-bin/program.py?VAR1=WERT1&VAR2=WERT2&VAR3=WERT3`"

  - "`https://www.foo.dom/program.php?VAR1=WERT1&VAR2=WERT2&VAR3=WERT3`"

- "`%nn`" in einer URL wird durch ein Zeichen mit hexadezimalem `nn`-Wert ersetzt.

- Die Umgebungsvariable wird gesetzt als: "`ABFRAGE_STRING="VAR1=WERT1 VAR2=WERT2 VAR3=WERT3"`".

- Ein CGI-Programm (irgendeines von "`program.*`") auf dem Webserver führt sich selbst mit der Umgebungsvariable "`$ABFRAGE_STRING`" aus.

- Die Standardausgabe (`stdout`) eines CGI-Programms wird zum Webbrowser gesandt und dort als interaktive dynamische Webseite angezeigt.

Aus Sicherheitsgründen wird empfohlen, keinen eigenen zusammengebastelten Code zum Parsen von CGI-Parametern zu verwenden. Es gibt dafür etablierte Module in Perl und Python. PHP unterstützt diese Funktionalitäten. Wenn eine Speicherung der Daten auf dem Client nötig ist, werden HTTP-Cookies verwendet. Ist eine Verarbeitung der Daten auf dem Client erforderlich, wird häufig Javascript genutzt.

Für weitere Informationen wird auf das Common Gateway Interface, die Apache Software Foundation und JavaScript verwiesen.

Die Suche nach "CGI tutorial" auf Google durch Eingabe der kodierten URL https://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial direkt in der Adresszeile des Browsers ist eine gute Möglichkeit, das CGI-Skript auf dem Google-Server in Aktion zu beobachten.

## 12.8. Die Quellcode-Übersetzung

Es gibt verschiedene Programme zur Übersetzung von Quellcode:

Tabelle 12.19. Liste von Programmen zur Übersetzung von Quellcode

Paket | Popcon | Größe | Schlüsselwort | Beschreibung
--- | --- | --- | --- | ---
`perl` | V:668, I:992 | 838 | AWK → PERL | Quellcode von AWK nach PERL konvertieren: a2p(1)
`f2c` | V:0.1, I:2.0 | 443 | FORTRAN → C | Quellcode von FORTRAN 77 nach C/C++ konvertieren: f2c(1)
`intel2gas` | V:0.03, I:0.18 | 178 | intel → gas | Konvertierer von NASM (Intel-Format) nach GNU Assembler (GAS)

## 12.9. Erstellen von Debian-Paketen

Wenn Sie ein Debian-Paket erstellen möchten, lesen Sie folgendes:

- Kapitel 2, Debian-Paketmanagement, um die Grundlagen des Paketsystems zu verstehen;

- Abschnitt 2.7.13, „Ein Paket auf das Stable-System portieren“, um den grundlegenden Portierungsprozess zu verstehen;

- Abschnitt 9.11.4, „Chroot-System“, um die grundlegenden chroot-Techniken zu verstehen;

- debuild(1) und sbuild(1)

- Abschnitt 12.5.2, „Fehlersuche (Debugging) in einem Debian-Paket“ für Informationen zum Rekompilieren von Quellcode zwecks Fehlersuche (Debugging);

- Handbuch für Debian-Paketbetreuer (aus dem `debmake-doc`-Paket).

- Debian-Entwicklerreferenz (aus dem `developers-reference`-Paket);

- Debian Policy-Handbuch (aus dem `debian-policy`-Paket);

Es gibt auch Pakete wie `debmake`, `dh-make`, `dh-make-perl` usw., die beim Paketieren helfen.

[7] Einige Kniffe könnten erforderlich sein, um sie auf dem aktuellen System zum Laufen zu bringen.

Kapitel 11. Datenkonvertierung |  | Anhang A. Anhang