db41258d16
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>
105 lines
4.2 KiB
CMake
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}")
|