Kapitel 12. Programmierung

Inhaltsverzeichnis

12.1. Das Shell-Skript
12.1.1. POSIX-Shell-Kompatibilität
12.1.2. Shell-Parameter
12.1.3. Bedingte Ausdrücke in der Shell
12.1.4. Shell-Schleifen
12.1.5. Shell-Umgebungsvariablen
12.1.6. Befehlsabfolge auf der Shell
12.1.7. Hilfsprogramme für Shell-Skripte
12.2. Skriptverarbeitung in Interpreter-Sprachen
12.2.1. Fehlersuche im Code für Interpreter-Sprachen
12.2.2. Grafisches GUI-Programm und Shell-Skripte
12.2.3. Eigene Aktionen im Dateimanager
12.2.4. Verrücktes bei kurzen Perl-Skripten
12.3. Programmieren in kompilierten Sprachen
12.3.1. C
12.3.2. Ein einfaches C-Programm (gcc)
12.3.3. Flex - ein besseres Lex
12.3.4. Bison - ein besseres Yacc
12.4. Werkzeuge zur statischen Code-Analyse
12.5. Fehlersuche (Debugging)
12.5.1. Grundlegende Ausführung von gdb
12.5.2. Fehlersuche (Debugging) in einem Debian-Paket
12.5.3. Gewinnen von Backtrace-Informationen
12.5.4. Erweiterte gdb-Befehle
12.5.5. Überprüfen der Abhängigkeiten von Bibliotheken
12.5.6. Werkzeuge zur dynamischen Aufrufverfolgung
12.5.7. Fehleranalyse bei X-Fehlern
12.5.8. Werkzeuge zur Erkennung von Speicherlecks
12.5.9. Disassemblieren von Binärdateien
12.6. Bauwerkzeuge
12.6.1. Make
12.6.2. Autotools
12.6.2.1. Kompilieren und Installieren eines Programms
12.6.2.2. Deinstallation eines Programms
12.6.3. Meson
12.7. Web
12.8. Die Quellcode-Übersetzung
12.9. Erstellen von Debian-Paketen

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] Warnung

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

[Achtung] Achtung

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

[Tipp] Tipp

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

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.

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.


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] Anmerkung

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

[Tipp] Tipp

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

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] 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] 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.



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

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.


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 CLI-Programme 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.

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.


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 <[email protected]>, 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.


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.

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)

Flex ist ein Lex-kompatibler schneller lexikalischer Analysegenerator.

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

Many simple examples can be found under "/usr/share/doc/flex/examples/". [7]

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


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.

Here is an example to create a simple terminal calculator program.

Let's create example.y:

/* 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);
}

Let's create, 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 */ }
%%

Then execute as follows from the shell prompt to try this:

$ 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

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] 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 2591 Asynchrone Lint-Engine für Vim 8 und NeoVim
vim-syntastic I:3 1379 Syntaxprüfungen für Vim
elpa-flycheck V:0, I:1 808 moderne on-the-fly Syntaxprüfung für Emacs
elpa-relint V:0, I:0 147 Fehlersuche mittels Regexp für Emacs-Lisp-Dateien
cppcheck-gui V:0, I:1 7224 Werkzeug für die statische C/C++-Code-Analyse (GUI)
shellcheck V:2, I:13 18987 Lint-Werkzeug für Shell-Skripte
pyflakes3 V:2, I:15 20 passive Prüfung von Python3-Programmen
pylint V:4, I:20 2018 Statisches Prüfprogramm für Python-Code
perl V:707, I:989 673 Interpreter mit internem statischen Code-Prüfmechanismus: B::Lint(3perl)
rubocop V:0, I:0 3247 statischer Code-Analyser für Ruby
clang-tidy V:2, I:11 21 clang-basiertes C++-Linter-Werkzeug
splint V:0, I:2 2320 Werkzeug zur statischen Überprüfung von C-Programmen auf Programmfehler
flawfinder V:0, I:0 205 Werkzeug zur Durchsuchung von Quellcode auf Sicherheitsschwächen
black V:3, I:13 660 kompromissloser Python-Code-Formatierer
perltidy V:0, I:4 2493 Einrücker und Neuformatierer für Perl-Skripte
indent V:0, I:7 431 Code-Formatierer für C
astyle V:0, I:2 785 Quelltextformatierer für C, C++, Objective-C, C# und Java
bcpp V:0, I:0 111 C(++)-Code schön machen
xmlindent V:0, I:1 53 Neuformatierung von XML-Datenströmen
global V:0, I:2 1908 Werkzeuge zum Suchen und Browsen in Quelltext
exuberant-ctags V:2, I:20 341 Erzeugen von Indexdateien aus Quelltextdefinitionen
universal-ctags V:1, I:11 3386 Erzeugen von Indexdateien aus Quelltextdefinitionen

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.


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] Tipp

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

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.

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:

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] 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

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.



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

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.

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 initially released in 2000 improved speed significantly but was originally built on the top of inherently slow Make. (Now Ninja can be its backend.)

  • Ninja initially released in 2012 is meant to replace Make for the further improved build speed and is designed to have its input files generated by a higher-level build system.

  • 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".

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.

Es gibt verschiedene Programme zur Übersetzung von Quellcode:


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

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



[7] Some tweaks may be required to get them work under the current system.