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