Files
playground/pda/CMakeLists.txt
T
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

105 lines
4.2 KiB
CMake

# ---------------------------------------------------------------------------
# pda - die Anwendung
#
# Eigenstaendiges Projekt (P1204R0), genau wie libpda. Der entscheidende
# Unterschied steht im else-Zweig unten: allein gebaut sucht die Anwendung
# libpda ueber find_package -- also genau so, wie ein FREMDES Projekt sie
# benutzen wuerde.
#
# Damit ist dieses CMakeLists.txt gleichzeitig der Beweis, dass der
# Export-Mechanismus in libpda/CMakeLists.txt funktioniert.
# ---------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.28)
project(pda
VERSION 0.1.0
DESCRIPTION "PDA: Kontakte, Rechner, Notizen, Dateien"
LANGUAGES CXX)
if(PROJECT_IS_TOP_LEVEL)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
include(ProjectDefaults)
include(Warnings)
include(Sanitizers)
option(PDA_BUILD_TESTS "Tests bauen" ON)
# Allein gebaut: libpda muss installiert und ueber CMAKE_PREFIX_PATH
# auffindbar sein.
#
# cmake -S pda -B build/nur-app -DCMAKE_PREFIX_PATH=/pfad/zur/installation
#
# REQUIRED sorgt fuer einen sofortigen, verstaendlichen Abbruch statt fuer
# einen Linkerfehler dreissig Zeilen spaeter.
find_package(pda 0.1 REQUIRED)
if(PDA_BUILD_TESTS)
enable_testing()
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../third_party" third_party)
endif()
endif()
# ---------------------------------------------------------------------------
# Die Logik als interne Bibliothek.
#
# Warum nicht einfach alles in die Executable: ein Unit-Test muesste dann
# shell.cpp erneut uebersetzen UND wuerde main.cpp mitziehen -- zwei
# main()-Funktionen in einer Executable sind ein Linkerfehler.
#
# Das Muster dagegen ist immer dasselbe und gilt weit ueber CMake hinaus:
# main.cpp bleibt duenn und macht nur Ein-/Ausgabe, alles Testbare wandert in
# eine Bibliothek. Hier ist sie STATIC und wird nicht installiert -- sie ist
# ein Bauhilfsmittel, kein Teil der Auslieferung.
# ---------------------------------------------------------------------------
add_library(pda_shell STATIC
pda/shell.cpp
pda/shell.hpp
)
# Der Include-Root ist das PROJEKTWURZELVERZEICHNIS (also pda/), nicht
# pda/pda. Nur so loest <pda/shell.hpp> auf pda/pda/shell.hpp auf.
#
# PUBLIC, weil sowohl die Executable als auch der Test <pda/shell.hpp>
# inkludieren -- beide erben den Pfad, statt ihn zu wiederholen.
target_include_directories(pda_shell PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
# PUBLIC bei pda::pda ist kein Versehen: shell.hpp inkludiert
# <libpda/contact.hpp> im INTERFACE. Wer pda_shell linkt, braucht die Header
# von libpda also ebenfalls. Waere das PRIVATE, wuerde shell.test.cpp mit
# "libpda/contact.hpp: No such file" scheitern.
target_link_libraries(pda_shell PUBLIC pda::pda)
target_link_libraries(pda_shell PRIVATE pda_warnings)
# ---------------------------------------------------------------------------
# Die Executable
#
# Targetname "pda_app", nicht "pda": im Superprojekt gibt es bereits ein
# Bibliothekstarget "pda", und zwei Targets duerfen nicht gleich heissen.
# Der DATEIname wird ueber OUTPUT_NAME trotzdem "pda" -- Targetname und
# Dateiname sind in CMake zwei verschiedene Dinge.
# ---------------------------------------------------------------------------
add_executable(pda_app pda/main.cpp)
set_target_properties(pda_app PROPERTIES OUTPUT_NAME pda)
target_link_libraries(pda_app PRIVATE pda_shell pda_warnings)
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
if(PDA_BUILD_TESTS)
if(TARGET doctest)
add_executable(shell.test pda/shell.test.cpp)
target_link_libraries(shell.test PRIVATE pda_shell doctest pda_warnings)
doctest_discover_tests(shell.test TEST_PREFIX "doctest.")
endif()
add_subdirectory(tests)
endif()
# ---------------------------------------------------------------------------
# Installation. Nur die Executable -- eine Anwendung exportiert keine Targets.
# ---------------------------------------------------------------------------
include(GNUInstallDirs)
install(TARGETS pda_app RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")