# Konventionen Was `clang-format` und `clang-tidy` nicht erzwingen können, steht hier. Mechanisch erzwungen wird bisher nur, was `clang-format` und `clang-tidy` abdecken. Ein `check_style.sh` gibt es in diesem Repo **nicht** (die CONVENTIONS.md von mydb verweist darauf, aber die Datei existiert dort ebenfalls nicht) — die folgenden Regeln gelten also per Konvention. ## Projektstruktur (P1204R0) Zwei eigenständige Projekte unter einem Superprojekt: ``` playground/ Superprojekt, kein eigener Quellcode ├── libpda/ project(libpda) -> libpda.a │ ├── libpda/ Quellcode UND Header zusammen │ │ ├── textfile.h public API (C) │ │ ├── textfile.c │ │ ├── textfile.test.c Unit-Test, direkt neben dem Modul │ │ ├── contact.hpp public API (C++) │ │ ├── contact.cpp │ │ ├── contact.test.cpp │ │ └── details/ Implementation Details, nicht public API │ └── tests/basics/ Integrationstests gegen die öffentliche API ├── pda/ project(pda) -> bin/pda │ ├── pda/ shell.hpp/.cpp, main.cpp │ └── tests/session/ ├── examples/consumer/ fremdes Projekt, find_package(pda) ├── third_party/ vendorter Fremdcode, nie editieren ├── cmake/ ProjectDefaults, Warnings, Sanitizers, pdaConfig.cmake.in └── docs/ CMAKE.md, diese Datei, ADRs ``` **Kein `include/` + `src/`.** Header und Implementierung liegen nebeneinander. Bei Templates, `inline` und Modulen ist die Trennung ohnehin nicht sauber zu ziehen, und der Verzeichnisname übernimmt die Rolle des Namespace im Dateisystem. **Bibliothek und Programm sind getrennte Projekte.** P1204R0 verlangt das; der praktische Grund ist, dass `libpda` ohne `pda` baubar sein muss. Die Probe: ```sh cmake -S libpda -B build/nur-lib && cmake --build build/nur-lib ``` **Ein Namespace, zwei Include-Wurzeln.** Beide Projekte benutzen `namespace pda` — auseinandergehalten wird über den Pfad: ```cpp #include // Bibliothek #include // Anwendung ``` Das ist genau das Schema aus P1204R0 (`libhello` / `hello`): das `lib`-Präfix steht im Projekt- und Verzeichnisnamen, nicht im Namespace. ## Includes **Eigene Header immer mit spitzen Klammern und Projektpräfix:** ```c #include /* richtig */ #include "textfile.h" /* falsch */ ``` Das ist P1204R0s wichtigste Einzelregel. Spitze Klammern durchsuchen nur die `-I`-Pfade, niemals das Verzeichnis der inkludierenden Datei — ein fehlender oder falsch installierter Header fällt damit sofort auf, statt dass zufällig ein gleichnamiger Nachbar gefunden wird. Reihenfolge macht `clang-format` (`IncludeBlocks: Regroup`): eigener Header, Projekt-Header, Test-Framework, C-Standardbibliothek, C++-Standardbibliothek, Rest. ## Extensions | Extension | Bedeutung | |---|---| | `.h` / `.c` | C | | `.hpp` / `.cpp` | C++ | | `.test.c` / `.test.cpp` | Unit-Test neben dem getesteten Modul | Die Extension sagt die Sprache. In einem gemischten Projekt ist das der Punkt — ein `.h` ist aus C **und** C++ benutzbar (der `extern "C"`-Block im Header), ein `.hpp` nur aus C++. ## Namen | Was | Form | Beispiel | |---|---|---| | Typen | `PascalCase` | `ContactBook`, `TextBuffer`, `Explorer` | | Funktionen, Variablen | `snake_case` | `human_size`, `line_count` | | Makros | `UPPER_CASE` mit Projektpräfix | `LIBPDA_TEXTFILE_H`, `PDA_EXPORT` | | C-API | Modulpräfix | `textfile_read`, `textfile_write`, `textfile_escape` | | Out-Parameter | `out_`-Präfix | `size_t* out_len` | | Member | blank, kein `m_`, kein `_` | `entries`, `rows`, `here` | | Namespace | Projektname ohne `lib` | `namespace pda` | ## Kommentare Ausschließlich `/* */`, niemals `//` — auch nicht einzeilig. Abschnitte werden so getrennt: ```c /* ---- API ---- */ ``` Kommentare sind auf Deutsch, **Umlaute transliteriert** (`ae oe ue ss`), damit die Quellen reines ASCII bleiben. README und öffentliche Header auf Englisch. Prüfen lässt sich das mit: ```sh grep -rlP '[^\x00-\x7F]' playground tests ``` ## Header `#ifndef LIBPDA_TEXTFILE_H` — Include-Guards, kein `#pragma once`. Öffentliche C-Header bekommen einen `extern "C"`-Block, damit die C++-Seite sie benutzen kann. Structs, deren Layout niemanden angeht, sind opak: `typedef struct Page Page;` im Header, die Definition in der `.c`. ## Tests **Unit-Test** (`.test.c` / `.test.cpp`) liegt neben dem Modul, kennt dessen Interna und ist eine eigenständige Executable. - C → Unity, registriert als CTest `unity.` (hier: `unity.textfile`) - C++ → doctest, `doctest_discover_tests()` legt **einen CTest-Eintrag pro `TEST_CASE`** an **Integrationstest** (`tests//driver.c` oder `.cpp`) benutzt nur die öffentliche API, kein Framework, Ergebnis über den Exit-Code. Er würde genauso gegen eine installierte Bibliothek laufen. TDD-Zyklus: RED (Test schlägt aus dem richtigen Grund fehl) → GREEN (kleinste Implementierung) → REFACTOR. ## Build Die ausführliche Erklärung steht in [CMAKE.md](CMAKE.md). Das Wichtigste: - Öffentliche Deklarationen der Bibliothek brauchen `PDA_EXPORT`, sonst exportiert der Shared-Bau sie nicht. - Neue Dateien immer von Hand in `LIBPDA_SOURCES` / `LIBPDA_HEADERS`. Kein `file(GLOB)`. Neue Dateien werden in `CMakeLists.txt` eingetragen — CMake merkt sonst nicht, dass eine Datei dazugekommen ist, der Build bleibt grün und die Datei fehlt einfach. | Preset | Zweck | |---|---| | `debug` | Alltag | | `release` | RelWithDebInfo | | `asan-ubsan` | AddressSanitizer + UBSan | | `apple-clang` | Portabilitätsprobe (macOS-System-Compiler) | | `homebrew-gcc` | Portabilitätsprobe (GCC-Frontend) | | `linux-gcc` | nur auf Linux sichtbar | `build//` — die Tiefe ist bindend: der neotest-CTest-Adapter sucht nur drei Ebenen tief, und der Neovim-Target-Picker leitet den File-API-Pfad daraus ab. ## Commits Conventional Commits: `feat:`, `fix:`, `test:`, `refactor:`, `chore:`, `docs:`. Aktuell ohne Hook — es gibt kein `check_style.sh`, das einen installieren könnte. ## Zwei Dinge, die wie Fehler aussehen, aber keine sind **Nach einem frischen Clone zeigt clangd nichts.** Es gibt noch kein `compile_commands.json`. Einmal `oc` (configure), dann ist alles da. Neovim weist beim Öffnen einer C/C++-Datei darauf hin. **Der Testbaum (`ts`) ist nach einem frischen Clone leer.** `doctest_discover_tests()` ruft die Test-Executable beim **Build** auf, um die `TEST_CASE`s aufzulisten. Vor dem ersten Build kennt CTest sie also nicht. Einmal `b`, dann füllt sich der Baum. ## Rückfallebene für die C-Tests Der neotest-Adapter für Unity (`nvim-local/neotest-unity`) ist selbst geschrieben, weil `neotest-ctest` `.c`-Dateien grundsätzlich nicht sieht. Wenn er je zur Last wird: aus der `adapters`-Liste in `nvim/lua/plugins/neotest.lua` entfernen, neotest bleibt für C++ zuständig, und die C-Tests laufen über `ot` (overseer → ctest → Quickfix). Dann fehlt der Rot/Grün-Baum für C, aber ein Tastendruck und Sprung zur Fehlerstelle bleiben.