cmake_minimum_required(VERSION 3.22) project(dpm-core VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) # --------------------------------------------------------------------- # libdpm-core.so — the library (C ABI) # --------------------------------------------------------------------- add_library(dpm-core SHARED src/context.cpp src/modules.cpp src/version.cpp ) target_include_directories(dpm-core PUBLIC $ $ ) target_compile_definitions(dpm-core PRIVATE DPM_CORE_VERSION_STR="${PROJECT_VERSION}" ) # The public C API is the library's entire exported surface; internals # stay hidden. The version script pins the export list and versions the # symbols. target_compile_options(dpm-core PRIVATE -fvisibility=hidden -fvisibility-inlines-hidden ) target_link_options(dpm-core PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/libdpm-core.map ) set_property(TARGET dpm-core APPEND PROPERTY LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/libdpm-core.map ) target_link_libraries(dpm-core PRIVATE ${CMAKE_DL_LIBS}) set_target_properties(dpm-core PROPERTIES OUTPUT_NAME "dpm-core" VERSION ${PROJECT_VERSION} SOVERSION 1 LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) # --------------------------------------------------------------------- # dpm — the CLI (thin client of libdpm-core) # --------------------------------------------------------------------- add_executable(dpm src/cli/dpm.cpp) target_link_libraries(dpm PRIVATE dpm-core) set_target_properties(dpm PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin BUILD_RPATH "$ORIGIN/../lib" ) # --------------------------------------------------------------------- # info — the bundled module (tests and reports libdpm-core functionality) # --------------------------------------------------------------------- add_library(info MODULE src/bundled-modules/info/info.cpp src/bundled-modules/info/src/commands.cpp ) target_include_directories(info PRIVATE src/bundled-modules/info/include) # The one permitted link dependency: libdpm-core. target_link_libraries(info PRIVATE dpm-core) set_target_properties(info PROPERTIES PREFIX "" SUFFIX ".so" LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/modules ) # The module bundles with libdpm-core, so building the CLI builds it too: after a # clean, running dpm from the build tree finds a module directory that is # populated. This orders the build only — the CLI does not link the module. add_dependencies(dpm info) # --------------------------------------------------------------------- # Test fixture modules: one known-good stub, five deliberately broken # --------------------------------------------------------------------- enable_testing() # CTest's scratch area is named by its BuildDirectory configuration option. # Writing it into DartConfiguration.tcl puts it where ctest reads it on every # invocation — the test target, a bare ctest, and the IDE's test discovery # alike — rather than only the ones the build drives. file(WRITE ${CMAKE_BINARY_DIR}/DartConfiguration.tcl "BuildDirectory: ${CMAKE_BINARY_DIR}/test-results\n") set(FIXTURE_MODULE_DIR ${CMAKE_BINARY_DIR}/tests/fixtures) foreach(fixture good missing_symbols bad_magic lying_manifest core_too_new bad_version) add_library(fixture_${fixture} MODULE tests/fixtures/src/${fixture}.cpp) set_target_properties(fixture_${fixture} PROPERTIES PREFIX "" SUFFIX ".so" OUTPUT_NAME ${fixture} LIBRARY_OUTPUT_DIRECTORY ${FIXTURE_MODULE_DIR} ) endforeach() # --------------------------------------------------------------------- # API test binary — drives libdpm-core through its public C API # --------------------------------------------------------------------- add_executable(test_core tests/test_core.cpp) target_link_libraries(test_core PRIVATE dpm-core) target_compile_definitions(test_core PRIVATE TEST_FIXTURE_MODULES="${FIXTURE_MODULE_DIR}" TEST_FIXTURE_CONF="${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/conf" DPM_CORE_VERSION_EXPECTED="${PROJECT_VERSION}" ) set_target_properties(test_core PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests BUILD_RPATH "$ORIGIN/../lib" ) foreach(fixture good missing_symbols bad_magic lying_manifest core_too_new bad_version) add_dependencies(test_core fixture_${fixture}) endforeach() add_test(NAME core_api COMMAND test_core) # --------------------------------------------------------------------- # CLI end-to-end tests (the dpm binary is the cheapest full-stack client) # --------------------------------------------------------------------- add_test(NAME cli_help COMMAND dpm --help) set_tests_properties(cli_help PROPERTIES PASS_REGULAR_EXPRESSION "Usage: dpm") add_test(NAME cli_list COMMAND dpm -c ${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/conf -m ${CMAKE_BINARY_DIR}/modules --list-modules) set_tests_properties(cli_list PROPERTIES PASS_REGULAR_EXPRESSION "info") add_test(NAME cli_info_version COMMAND dpm -c ${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/conf -m ${CMAKE_BINARY_DIR}/modules -L INFO info version) set_tests_properties(cli_info_version PROPERTIES PASS_REGULAR_EXPRESSION "libdpm-core Version: ${PROJECT_VERSION}") add_test(NAME cli_module_not_found COMMAND dpm -c ${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/conf -m ${CMAKE_BINARY_DIR}/modules nonexistent) set_tests_properties(cli_module_not_found PROPERTIES WILL_FAIL TRUE) add_test(NAME cli_rejects_invalid_module COMMAND dpm -c ${CMAKE_CURRENT_SOURCE_DIR}/tests/fixtures/conf -m ${FIXTURE_MODULE_DIR} missing_symbols) set_tests_properties(cli_rejects_invalid_module PROPERTIES WILL_FAIL TRUE) # --------------------------------------------------------------------- # Code reference (Doxygen) — optional 'docs' target # --------------------------------------------------------------------- option(DPM_DOCS_HTML "Generate the code reference in HTML" OFF) option(DPM_DOCS_PDF "Generate the code reference as PDF (requires LaTeX)" ON) find_package(Doxygen) if(DOXYGEN_FOUND) set(DOXYGEN_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/docs) set(DOXYGEN_EXTRACT_ALL YES) set(DOXYGEN_EXTRACT_STATIC YES) set(DOXYGEN_QUIET YES) set(DOXYGEN_WARN_IF_UNDOCUMENTED NO) set(DOXYGEN_JAVADOC_AUTOBRIEF YES) if(DPM_DOCS_HTML) set(DOXYGEN_GENERATE_HTML YES) else() set(DOXYGEN_GENERATE_HTML NO) endif() if(DPM_DOCS_PDF) set(DOXYGEN_GENERATE_LATEX YES) set(DOXYGEN_USE_PDFLATEX YES) set(DOXYGEN_PDF_HYPERLINKS YES) else() set(DOXYGEN_GENERATE_LATEX NO) endif() doxygen_add_docs(docs ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src COMMENT "Generating code reference with Doxygen" ) if(DPM_DOCS_PDF) find_program(PDFLATEX_EXECUTABLE pdflatex) if(PDFLATEX_EXECUTABLE) add_custom_target(docs-pdf COMMAND make -C ${CMAKE_BINARY_DIR}/docs/latex COMMENT "Building PDF code reference" ) add_dependencies(docs-pdf docs) else() message(WARNING "DPM_DOCS_PDF is ON but pdflatex was not found; the docs-pdf target is unavailable") endif() endif() endif() # --------------------------------------------------------------------- # Clean # --------------------------------------------------------------------- # clean removes what the build produced: the artifact directories, the # generated documentation, and the test scratch areas. # # The generated build system stays. CMakeCache.txt, the makefiles, # CMakeFiles/, and the CMake file API directory under .cmake/ are what an # IDE reads to know the project's targets exist; deleting them leaves the # directory unconfigured, so every target in the IDE stops resolving until # the project is reloaded. Removing the build system is what configuring a # fresh directory is for. set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${CMAKE_BINARY_DIR}/test-results ${CMAKE_BINARY_DIR}/Testing ${CMAKE_BINARY_DIR}/bin ${CMAKE_BINARY_DIR}/lib ${CMAKE_BINARY_DIR}/modules ${CMAKE_BINARY_DIR}/tests ${CMAKE_BINARY_DIR}/docs ) # --------------------------------------------------------------------- # Installation # --------------------------------------------------------------------- install(TARGETS dpm RUNTIME DESTINATION bin) install(TARGETS dpm-core LIBRARY DESTINATION lib) install(TARGETS info LIBRARY DESTINATION lib/dpm/modules) install(DIRECTORY include/dpm DESTINATION include) install(FILES data/core.conf DESTINATION /etc/dpm/conf.d)