Files
dpm-core-ng/CMakeLists.txt
Christopher M. Punches b641318663 Store the version in version.cpp and group the library under src/core
libdpm-core.so's version was reaching the source as a compile-line
definition, with a fallback in two translation units that would have let
the library build and report 0.0.0 if the build ever stopped supplying
it. The version is a literal in src/core/version.cpp, the file named for
it, alongside dpm_core_version() which returns it and the parser for the
X.Y.Z strings modules report.

The library's sources and its version script move to src/core, leaving
src/cli, src/bundled-modules, and the documentation source beside it.
2026-08-15 22:57:46 -04:00

281 lines
11 KiB
CMake

cmake_minimum_required(VERSION 3.22)
project(dpm-core VERSION 1.0.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/core/context.cpp
src/core/modules.cpp
src/core/version.cpp
)
target_include_directories(dpm-core PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# 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/core/libdpm-core.map
)
set_property(TARGET dpm-core APPEND PROPERTY
LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/core/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, two 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_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_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" ON)
option(DPM_DOCS_PDF "Generate the code reference as PDF (requires LaTeX)" ON)
find_package(Doxygen)
if(DOXYGEN_FOUND)
# Doxygen and LaTeX both work in scratch space under docs/tmp. The
# finished document is copied up into docs/, so the directory a user
# opens holds documentation and nothing else.
set(DOXYGEN_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/docs/tmp)
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()
# The prose documents, each rendered as its own page in the generated
# reference. Named one per line so the set of documents reaching the
# output is stated here instead of implied by a directory.
set(DPM_DOC_PAGES
${CMAKE_CURRENT_SOURCE_DIR}/docs/OVERVIEW.md
${CMAKE_CURRENT_SOURCE_DIR}/docs/DESIGN.md
${CMAKE_CURRENT_SOURCE_DIR}/docs/CONSUMERS.md
${CMAKE_CURRENT_SOURCE_DIR}/docs/MODULES.md
${CMAKE_CURRENT_SOURCE_DIR}/docs/BUILD.md
${CMAKE_CURRENT_SOURCE_DIR}/docs/DOCUMENTATION.md
)
# Two kinds of input: include/ and src/ supply the API and internals
# reference extracted from the source, DPM_DOC_PAGES supplies the
# prose pages.
#
# One target, so `cmake --build <dir> --target docs` is the whole
# procedure and the IDE lists a single entry for it. The commands
# below run after Doxygen and place the finished documents.
doxygen_add_docs(docs
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${DPM_DOC_PAGES}
COMMENT "Generating the reference with Doxygen"
)
if(DPM_DOCS_PDF)
find_program(PDFLATEX_EXECUTABLE pdflatex)
if(PDFLATEX_EXECUTABLE)
add_custom_command(TARGET docs POST_BUILD
COMMAND make -C ${CMAKE_BINARY_DIR}/docs/tmp/latex
COMMAND ${CMAKE_COMMAND} -E rm -rf
${CMAKE_BINARY_DIR}/docs/pdf
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_BINARY_DIR}/docs/tmp/latex/refman.pdf
${CMAKE_BINARY_DIR}/docs/pdf/dpm-core-${PROJECT_VERSION}.pdf
COMMENT "Compiling the PDF reference"
)
else()
message(WARNING "DPM_DOCS_PDF is ON but pdflatex was not found; no PDF will be produced")
endif()
endif()
if(DPM_DOCS_HTML)
add_custom_command(TARGET docs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rm -rf
${CMAKE_BINARY_DIR}/docs/html
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_BINARY_DIR}/docs/tmp/html
${CMAKE_BINARY_DIR}/docs/html
COMMENT "Placing the HTML reference"
)
endif()
# Doxygen keeps output files it judges unchanged, so a run over a
# populated scratch directory can carry pages forward from an earlier
# one. Removing it here means the next run regenerates everything,
# and leaves docs/ holding the finished documents alone.
add_custom_command(TARGET docs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_BINARY_DIR}/docs/tmp
COMMENT "Clearing the generators' scratch directory"
)
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)