Files
playground/docs/adr/0002-pda-aufteilung.md
paulhorn db41258d16 feat: PDA als libpda + pda nach P1204R0
Ersetzt das Geruest (counter/notebook) durch ein echtes Beispiel und teilt
es in zwei eigenstaendige Projekte, wie P1204R0 es fuer Bibliothek plus
Programm verlangt.

libpda: textfile (C, Datei-I/O und Feld-Escaping), calculator
(Recursive-Descent-Parser mit std::expected), contact, editor, explorer.
Exportiert pda::pda ueber install(EXPORT) und ist per find_package(pda)
benutzbar.

pda: Shell ohne Ein-/Ausgabe (execute() gibt Text zurueck, deshalb ohne
Terminal testbar), REPL und Stapelbetrieb in main.cpp.

examples/consumer und tools/check-install.sh pruefen die Export-Kette
Ende-zu-Ende: installieren, dann ein fremdes Projekt dagegen bauen.

docs/CMAKE.md erklaert das Target-Modell, PUBLIC/PRIVATE/INTERFACE,
Generator-Ausdruecke, install/export und Symbolsichtbarkeit an diesem
Projekt.

71 Tests gruen unter Homebrew-clang 22, Apple clang und GCC 16, statisch
und shared, mit und ohne ASan/UBSan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 16:39:35 +02:00

68 lines
2.8 KiB
Markdown

# ADR 0002 — Aufteilung in libpda und pda
- Status: akzeptiert
- Datum: 2026-08-30
## Kontext
Das Projekt soll einen kleinen PDA umsetzen (Kontakte, Rechner, Notizen,
Dateiexplorer) und dabei ausdrücklich als **Bibliothek** benutzbar sein — man
soll damit eigene Sachen bauen können.
P1204R0 sagt dazu: „If a project consists of a library and an executable, then
they should be split into separate projects."
Die naheliegende Alternative wäre ein Projekt mit einem `pda_core`-Target und
einer Executable daneben — so machen es `mydb` und `cxx_scaffold_cli`.
## Entscheidung
Zwei eigenständige Projekte unter einem Superprojekt:
- `libpda/` mit eigenem `project(libpda)`, exportiert `pda::pda`
- `pda/` mit eigenem `project(pda)`, linkt `pda::pda`
Beide sind einzeln konfigurierbar. `pda/CMakeLists.txt` benutzt im
Alleinbetrieb `find_package(pda REQUIRED)`.
## Konsequenzen
Die Bibliothek ist nachweislich unabhängig: `cmake -S libpda -B build/nur-lib`
baut und testet sie ohne die Anwendung (47 der 71 Tests).
Die Anwendung ist damit gleichzeitig der Integrationstest für den
Export-Mechanismus. Was sie im Alleinbetrieb tut, tut auch jedes fremde
Projekt.
`examples/consumer/` und `tools/check-install.sh` machen das explizit: das
Skript installiert `libpda` in ein temporäres Präfix und baut ein fremdes
Programm dagegen. Genau diese Kette fängt den häufigsten Verteilungsfehler —
ein `target_include_directories` ohne `BUILD_INTERFACE`/`INSTALL_INTERFACE`
zeigt beim Benutzer ins Leere und fällt im eigenen Build nie auf.
Der Preis ist eine Ebene mehr im Pfad (`libpda/libpda/contact.hpp`) und der
`PROJECT_IS_TOP_LEVEL`-Block in beiden Teilprojekten. Beides ist der Preis
dafür, dass „Bibliothek" hier nicht nur ein Wort ist.
## Nebenentscheidungen
**Ein Namespace für beide Projekte** (`namespace pda`), unterschieden über den
Include-Pfad — so wie `libhello`/`hello` in P1204R0. Das `lib`-Präfix steht im
Projekt- und Verzeichnisnamen, nicht im Namespace.
**Die C-Schicht ist echt, nicht dekorativ.** `textfile.c` macht Datei-I/O und
Feld-Escaping — die Stelle, an der Besitzverhältnisse und rohe Puffer
sichtbar sind. Alles darüber ist C++ und verpackt das in RAII. Die Naht ist in
`contact.cpp` zu sehen: `unique_ptr` mit eigenem Deleter um die `char*`, die
`textfile_escape` liefert.
**`std::expected` statt Exceptions** für Benutzerfehler (Tippfehler im
Ausdruck, fehlende Datei). Ein Parser-Fehler ist der Normalfall dieser
Funktionen, kein Ausnahmezustand. Exceptions bleiben für das, was wirklich
nicht vorgesehen ist.
**Die Shell kennt keine Ein-/Ausgabe.** `Shell::execute()` bekommt eine Zeile
und gibt Text zurück; wer ihn anzeigt, ist ihre Sache nicht. Deshalb braucht
kein einziger der Shell-Tests ein Terminal, und eine GUI ließe sich ohne
Änderung an `shell.cpp` davorsetzen.