cmake_minimum_required(VERSION 3.14) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) project(essim LANGUAGES CXX VERSION 0.1 DESCRIPTION "System digital twin." ) include(FetchContent) # Shared CMake helpers (essim_add_frontend — per-frontend target boilerplate). list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(EssimFrontend) # ----------------------------------------------------------------- core deps # libbsdl — standalone BSDL parser (LGPL-2.1), dynamically linked (EUPL-1.2, # which the LGPL permits). Override its path with -DBSDL_DIR=... set(BSDL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../libbsdl" CACHE PATH "libbsdl source tree") set(BSDL_BUILD_CLI OFF CACHE BOOL "" FORCE) set(BSDL_BUILD_TESTS OFF CACHE BOOL "" FORCE) add_subdirectory(${BSDL_DIR} ${CMAKE_BINARY_DIR}/libbsdl) find_package(libzip REQUIRED) find_package(pugixml REQUIRED) # =============================================================== essim_core # All business logic — domain model, importers, application operations # (src/core/{domain,imports,app}). Frontend-agnostic: it links NO GUI/TUI # toolkit, so every frontend and the test suite share the exact same core. file(GLOB_RECURSE CORE_SOURCES "src/core/*.cpp") add_library(essim_core STATIC ${CORE_SOURCES}) target_include_directories(essim_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) target_link_libraries(essim_core PUBLIC libzip::zip pugixml::pugixml bsdl::bsdl ) # =============================================================== frontend(s) # Pick the GUI/TUI frontend to build the `essim` binary against. Each frontend # is a self-contained src/frontends// (own CMakeLists, GUI toolkit, and # main.cpp) that links essim_core. "none" builds the core + tests only — no GUI # toolkit is fetched. To add a frontend (e.g. a Qt GUI), create # src/frontends/gui/ and configure with -DESSIM_FRONTEND=gui. set(ESSIM_FRONTEND "tui" CACHE STRING "Frontend to build: a directory name under src/frontends/, or 'none'") set_property(CACHE ESSIM_FRONTEND PROPERTY STRINGS tui wx none) if(ESSIM_FRONTEND STREQUAL "none") message(STATUS "essim: ESSIM_FRONTEND=none — core + tests only (no frontend, no GUI toolkit)") elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/frontends/${ESSIM_FRONTEND}/CMakeLists.txt") message(STATUS "essim: building frontend '${ESSIM_FRONTEND}'") # Shared, GUI-toolkit-free frontend support: the abstract Frontend interface # (header-only) and the frontend-agnostic launcher frontend_main(). Every # frontend's main() links this and forwards argv to it. add_library(essim_frontend STATIC "${CMAKE_CURRENT_SOURCE_DIR}/src/frontends/frontend_main.cpp") target_include_directories(essim_frontend PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) add_subdirectory(src/frontends/${ESSIM_FRONTEND}) else() message(FATAL_ERROR "Unknown ESSIM_FRONTEND '${ESSIM_FRONTEND}' — expected " "src/frontends/${ESSIM_FRONTEND}/CMakeLists.txt, or 'none'.") endif() # =============================================================== tests (core) # The suite exercises essim_core only — no frontend, no GUI toolkit. include(CTest) if(BUILD_TESTING) set(CMAKE_POLICY_VERSION_MINIMUM 3.5) FetchContent_Declare(doctest GIT_REPOSITORY https://github.com/doctest/doctest.git GIT_TAG v2.4.11 GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(doctest) unset(CMAKE_POLICY_VERSION_MINIMUM) # Core tests — exercise essim_core only (tests/*.cpp, non-recursive, so the # per-frontend tests under tests// are not pulled in here). file(GLOB TEST_SOURCES "tests/*.cpp") if(TEST_SOURCES) add_executable(essim_tests ${TEST_SOURCES}) target_link_libraries(essim_tests PRIVATE essim_core doctest::doctest) add_test(NAME essim_tests COMMAND essim_tests) endif() # Per-frontend tests — tests//*.cpp, built and linked against that # frontend's library only when the frontend itself is built. if(TARGET essim_tui) file(GLOB TUI_TEST_SOURCES "tests/tui/*.cpp") if(TUI_TEST_SOURCES) add_executable(essim_tui_tests "${CMAKE_CURRENT_SOURCE_DIR}/tests/doctest_main.cpp" ${TUI_TEST_SOURCES}) target_link_libraries(essim_tui_tests PRIVATE essim_tui doctest::doctest) add_test(NAME essim_tui_tests COMMAND essim_tui_tests) endif() endif() endif() # =============================================================== documentation # Doxygen → XML → gen_api_md.py → doc/api/, plus `essim --commands-md`. Needs the # `essim` binary, so it's only wired when a frontend that provides one is built. find_package(Doxygen COMPONENTS doxygen) find_package(Python3 COMPONENTS Interpreter) if(TARGET essim AND DOXYGEN_FOUND AND Python3_Interpreter_FOUND) set(DOXYGEN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/doc") file(MAKE_DIRECTORY "${DOXYGEN_OUTPUT_DIR}") configure_file( "${CMAKE_SOURCE_DIR}/doc/Doxyfile.in" "${DOXYGEN_OUTPUT_DIR}/Doxyfile" @ONLY) set(DOC_API_DIR "${CMAKE_SOURCE_DIR}/doc/api") set(DOC_USER_DIR "${CMAKE_SOURCE_DIR}/doc/user") add_custom_target(doc DEPENDS essim COMMAND ${CMAKE_COMMAND} -E rm -rf "${DOC_API_DIR}" COMMAND ${CMAKE_COMMAND} -E make_directory "${DOC_API_DIR}/classes" COMMAND ${CMAKE_COMMAND} -E make_directory "${DOC_API_DIR}/files" COMMAND ${CMAKE_COMMAND} -E make_directory "${DOC_USER_DIR}" COMMAND ${DOXYGEN_EXECUTABLE} "${DOXYGEN_OUTPUT_DIR}/Doxyfile" COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/doc/gen_api_md.py" "${DOXYGEN_OUTPUT_DIR}/xml" "${DOC_API_DIR}" COMMAND $ --commands-md "${DOC_USER_DIR}/commands.md" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" COMMENT "Generating documentation (doxygen → gen_api_md.py → doc/api/, essim --commands-md → doc/user/commands.md)" VERBATIM) elseif(NOT TARGET essim) message(STATUS "doc: no `essim` binary (ESSIM_FRONTEND=none) — `doc` target disabled.") elseif(NOT DOXYGEN_FOUND) message(STATUS "doc: Doxygen not found — `doc` target disabled.") else() message(STATUS "doc: Python 3 interpreter not found — `doc` target disabled.") endif()