Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ option(MXLIB_USE_OPENMP "Whether or not to use OpenMP in mxlib and other librari

option(MXLIB_USE_CUDA "Whether or not to use CUDA library for mxlib" ON)
option(MXLIB_USE_ISIO "Whether or not to use the ImageStreamIO library for mxlib" ON)
option(MXLIB_BUILD_TESTS "Whether or not to build mxlib tests" OFF)
option(MXLIB_BUILD_COVERAGE "Whether or not to enable coverage instrumentation for C/C++ builds" OFF)
set(MXLIB_COVERAGE_TEST_TIMEOUT 300 CACHE STRING "CTest timeout (seconds) for coverage target")
option(MXLIB_BUILD_DOCS "Whether or not to build Doxygen docs as part of the default build" OFF)

set(MXLIB_USE_FFT_FROM "fftw" CACHE STRING "Which library to use for the FFT interface in mxlib")

Expand Down Expand Up @@ -360,6 +364,18 @@ set(CMAKE_CXX_FLAGS "${MXLIB_CXXVERSION} ${MXLIB_OPTIMIZE} ${MXLIB_CXXFLAGS}")

set(MXLIB_PC_CFLAGS "${MXLIB_PC_CFLAGS} ${CMAKE_CXX_FLAGS} ${MXLIB_DEFINES}")

if(MXLIB_BUILD_COVERAGE)
# Match the legacy Make coverage behavior: --coverage and -O0 for instrumented builds.
add_compile_definitions(MXLIB_BUILD_COVERAGE=1)
add_compile_options(
$<$<COMPILE_LANGUAGE:C>:--coverage>
$<$<COMPILE_LANGUAGE:C>:-O0>
$<$<COMPILE_LANGUAGE:CXX>:--coverage>
$<$<COMPILE_LANGUAGE:CXX>:-O0>
)
add_link_options(--coverage)
endif()

############################################
# OpenMP setup
############################################
Expand Down Expand Up @@ -785,4 +801,93 @@ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc

install( PROGRAMS gengithead.sh DESTINATION bin)

############################################
# Tests
############################################

if(MXLIB_BUILD_TESTS)
include(CTest)
add_subdirectory(tests)
else()
add_subdirectory(tests EXCLUDE_FROM_ALL)
endif()

add_custom_target(tests
DEPENDS mxlibTests
)

set(MXLIB_COVERAGE_BUILD_DIR ${CMAKE_BINARY_DIR}/coverage-build)
set(MXLIB_COVERAGE_INFO ${CMAKE_BINARY_DIR}/coverage.info)
set(MXLIB_COVERAGE_FILTERED_INFO ${CMAKE_BINARY_DIR}/coverage_filtered.info)
set(MXLIB_DOC_OUTPUT_DIR ${CMAKE_BINARY_DIR}/doc)
set(MXLIB_DOC_HTML_DIR ${MXLIB_DOC_OUTPUT_DIR}/html)
set(MXLIB_COVERAGE_REPORT_DIR ${MXLIB_DOC_HTML_DIR}/coverage)

find_package(Doxygen QUIET)

if(Doxygen_FOUND)
set(MXLIB_DOXYGEN_CONFIG_IN ${CMAKE_SOURCE_DIR}/doc/mxlib_doxygen.in)
set(MXLIB_DOXYGEN_CONFIG ${CMAKE_BINARY_DIR}/mxlib_doxygen)
set(MXLIB_DOXYGEN_OUTPUT_DIRECTORY ${MXLIB_DOC_OUTPUT_DIR})

configure_file(${MXLIB_DOXYGEN_CONFIG_IN} ${MXLIB_DOXYGEN_CONFIG} @ONLY)

if(MXLIB_BUILD_DOCS)
set(_mxlib_docs_all ALL)
else()
set(_mxlib_docs_all)
endif()

add_custom_target(docs ${_mxlib_docs_all}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MXLIB_DOC_OUTPUT_DIR}
COMMAND ${DOXYGEN_EXECUTABLE} ${MXLIB_DOXYGEN_CONFIG}
COMMAND ${CMAKE_COMMAND} -DCOVERAGE_REPORT_DIR=${MXLIB_COVERAGE_REPORT_DIR} -P ${CMAKE_SOURCE_DIR}/cmake/ensure_coverage_placeholder.cmake
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/doc
DEPENDS ${MXLIB_DOXYGEN_CONFIG}
${CMAKE_SOURCE_DIR}/doc/mxlib_header.html
${CMAKE_SOURCE_DIR}/doc/mxlibDoxygenLayout.xml
${CMAKE_SOURCE_DIR}/doc/main.dox
${CMAKE_SOURCE_DIR}/doc/coverage_report.dox
${CMAKE_SOURCE_DIR}/cmake/ensure_coverage_placeholder.cmake
USES_TERMINAL
)
else()
message(WARNING "doxygen not found. The docs target will not be available.")
endif()

find_program(MXLIB_LCOV_EXECUTABLE lcov)
find_program(MXLIB_GENHTML_EXECUTABLE genhtml)

if(MXLIB_LCOV_EXECUTABLE AND MXLIB_GENHTML_EXECUTABLE)
add_custom_target(coverage
COMMAND ${CMAKE_COMMAND} -S ${CMAKE_SOURCE_DIR} -B ${MXLIB_COVERAGE_BUILD_DIR} -DMXLIB_BUILD_TESTS=ON -DMXLIB_BUILD_COVERAGE=ON -DMXLIB_USE_CUDA=OFF -DMXLIB_USE_OPENMP=${MXLIB_USE_OPENMP} -DMXLIB_USE_ISIO=${MXLIB_USE_ISIO} -DMXLIB_USE_FFT_FROM=${MXLIB_USE_FFT_FROM} -DMXLIB_USE_BLAS_FROM=${MXLIB_USE_BLAS_FROM}
COMMAND ${CMAKE_COMMAND} --build ${MXLIB_COVERAGE_BUILD_DIR} --target mxlibTests -j
COMMAND ${MXLIB_LCOV_EXECUTABLE} --directory ${MXLIB_COVERAGE_BUILD_DIR} --zerocounters
COMMAND ${CMAKE_CTEST_COMMAND} --test-dir ${MXLIB_COVERAGE_BUILD_DIR} --output-on-failure --timeout ${MXLIB_COVERAGE_TEST_TIMEOUT}
COMMAND ${MXLIB_LCOV_EXECUTABLE} --directory ${MXLIB_COVERAGE_BUILD_DIR} --capture --output-file ${MXLIB_COVERAGE_INFO}
COMMAND ${MXLIB_LCOV_EXECUTABLE} --remove ${MXLIB_COVERAGE_INFO} ${CMAKE_SOURCE_DIR}/tests/* /usr/* /sys/* /tty/* --ignore-errors unused,unused --ignore-errors inconsistent,inconsistent --output-file ${MXLIB_COVERAGE_FILTERED_INFO}
COMMAND ${CMAKE_COMMAND} -E make_directory ${MXLIB_COVERAGE_REPORT_DIR}
COMMAND ${MXLIB_GENHTML_EXECUTABLE} ${MXLIB_COVERAGE_FILTERED_INFO} --output-directory ${MXLIB_COVERAGE_REPORT_DIR} --title mxlib --hierarchical --merge-aliases --suppress-aliases --filter function --demangle-cpp --css-file ${CMAKE_SOURCE_DIR}/tests/coverage/gcov.css
USES_TERMINAL
)
if(TARGET docs)
add_dependencies(coverage docs)
endif()
else()
message(WARNING "lcov/genhtml not found. The coverage target will not be available.")
endif()

add_custom_target(coverage_clean
COMMAND ${CMAKE_COMMAND} -E rm -f ${MXLIB_COVERAGE_INFO}
COMMAND ${CMAKE_COMMAND} -E rm -f ${MXLIB_COVERAGE_FILTERED_INFO}
COMMAND ${CMAKE_COMMAND} -E rm -rf ${MXLIB_COVERAGE_REPORT_DIR}
COMMAND ${CMAKE_COMMAND} -E rm -rf ${MXLIB_COVERAGE_BUILD_DIR}
)

if(TARGET docs)
add_custom_target(docs_clean
COMMAND ${CMAKE_COMMAND} -E rm -rf ${MXLIB_DOC_OUTPUT_DIR}
)
endif()

#dump_cmake_variables(".")
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ The documentation is located here: https://jaredmales.github.io/mxlib-doc/

See the [User's Guide](https://jaredmales.github.io/mxlib-doc/modules.html) for [installation instructions](https://jaredmales.github.io/mxlib-doc/group__installation.html)

See the [Testing](https://jaredmales.github.io/mxlib-doc/group__mxlib__testing.html)
section for test build, test execution, and coverage instructions.
65 changes: 65 additions & 0 deletions agent_context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Follow these code style and documentation rules exactly.

1) File-Level Documentation
- Each header/source should have a top Doxygen file block:
- \file
- \brief
- \author (if project uses it)

2) Include Guards and Includes
- Match existing project include-guard naming convention.
- Keep include ordering consistent with project style.
- Do not introduce new include style unless project already uses it.

3) Function Declaration Documentation
- Every function declaration must have a brief `///` summary.
- Add a short `/** ... */` details block only when needed.
- Document every parameter inline at declaration site using:
- `type name /**< [in] description */`
- Apply to normal methods, constructors, slots, and signals.
- Keep return-value docs where project uses them.

4) Member Variable Documentation
- Document non-trivial class members with `///`.
- Describe role/ownership/state, not just type.

5) Naming and Structure
- Use project member naming convention (e.g. `m_` prefix).
- Keep declaration ordering/grouping stable:
- public/protected/private
- slots/signals grouped consistently.
- Leave a blank line between declarations for readability.

6) Header vs Source Placement
- Keep non-trivial definitions out of headers.
- Move implementations to `.cpp` unless intentionally inline.

7) Editing Discipline
- Preserve existing behavior unless explicitly requested.
- When renaming members/APIs, update all dependent call sites.
- Keep changes minimal and scoped.

8) Formatting and Verification
- Run `clang-format` on touched files.
- Ensure docs and naming are consistent after formatting.
- Report any places where project style is ambiguous before making assumptions.

9) Doxygen Named Section Ordering
- For classes that expose configuration via member data + accessors, keep named sections split into:
- `... - Data` for protected/private member state
- `...` (without `- Data`) for public access functions
- Place the `... - Data` section before the corresponding public accessor section.

10) Header Declaration Parameter Docs
- In headers, prefer inline parameter documentation on declarations (`type name /**< ... */`) rather than separate `\param` lists, unless there is a specific reason to deviate.

11) PR Prompt Attribution
- At the top of PR descriptions, include an explicit attribution line when work was performed with Codex.
- Preferred format:
- `This work was performed by GPT-5.3-Codex in response to the prompt: "...".`
- Include the primary user prompt verbatim (or a faithful condensed version if it is extremely long).

When you finish:
- Summarize what changed.
- List affected files.
- Note any follow-up items or potential edge cases.
47 changes: 47 additions & 0 deletions cmake/ensure_coverage_placeholder.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
if(NOT DEFINED COVERAGE_REPORT_DIR OR COVERAGE_REPORT_DIR STREQUAL "")
message(FATAL_ERROR "COVERAGE_REPORT_DIR is required")
endif()

set(_coverage_index "${COVERAGE_REPORT_DIR}/index.html")

# Never overwrite a real coverage report.
if(EXISTS "${_coverage_index}")
message(STATUS "Coverage index already exists at ${_coverage_index}; leaving it unchanged.")
return()
endif()

file(MAKE_DIRECTORY "${COVERAGE_REPORT_DIR}")

file(WRITE "${_coverage_index}" "<!doctype html>
<html lang=\"en\">
<head>
<meta charset=\"utf-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
<title>mxlib coverage report</title>
<link href=\"../doxygen.css\" rel=\"stylesheet\" type=\"text/css\">
<link href=\"../doxygen-awesome.css\" rel=\"stylesheet\" type=\"text/css\">
<link href=\"../doxygen-awesome-sidebar-only.css\" rel=\"stylesheet\" type=\"text/css\">
<link href=\"../doxygen-awesome-sidebar-only-darkmode-toggle.css\" rel=\"stylesheet\" type=\"text/css\">
<style>
body {
font-family: var(--font-family, sans-serif);
color: var(--primary-foreground-color, #d0d7de);
background: var(--page-background-color, #1f2428);
margin: 2rem;
}
h1 { margin: 0 0 0.75rem 0; }
p { margin: 0.5rem 0; }
code {
font-family: var(--font-family-monospace, monospace);
color: var(--primary-foreground-color, #d0d7de);
}
</style>
</head>
<body>
<h1>Coverage report has not been generated.</h1>
<p>Run <code>cmake --build _build --target coverage</code> to generate it.</p>
</body>
</html>
")

message(STATUS "Wrote coverage placeholder at ${_coverage_index}")
100 changes: 100 additions & 0 deletions doc/building_tests.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/** \addtogroup testing_building
* @{
*
* Build tests on demand (always available, even if `MXLIB_BUILD_TESTS=OFF`):
*
* \code{.sh}
* cmake -S . -B _build
* cmake --build _build --target tests -j
* \endcode
*
* Configure with tests enabled:
*
* \code{.sh}
* cmake -S . -B _build -DMXLIB_BUILD_TESTS=ON
* \endcode
*
* With `MXLIB_BUILD_TESTS=ON`, test executables are part of the default build.
* With `MXLIB_BUILD_TESTS=OFF`, they are skipped by default and built only via
* `tests`/`mxlibTests` targets.
*
* Build all test executables:
*
* \code{.sh}
* cmake --build _build --target mxlibTests -j
* \endcode
*
* Run tests:
*
* \code{.sh}
* ctest --test-dir _build --output-on-failure
* \endcode
*
* Run the CTest test suite directly:
*
* \code{.sh}
* cmake --build _build --target mxlibTestRun
* \endcode
*
* Build and run a single test source (Makefile.one equivalent):
*
* \code{.sh}
* cmake -S . -B _build -DMXLIB_BUILD_TESTS=ON -DMXLIB_ONE_TEST=include/math/geo_test.cpp
* cmake --build _build --target mxlibTestOne -j
* cmake --build _build --target mxlibTestOneRun
* \endcode
*
* Coverage generation is integrated into CMake and modeled after the MagAOX flow.
*
* Prerequisites:
*
* \code{.sh}
* lcov --version
* genhtml --version
* \endcode
*
* Generate an HTML coverage report:
*
* \code{.sh}
* cmake -S . -B _build
* cmake --build _build --target coverage
* \endcode
*
* Build Doxygen docs directly from CMake:
*
* \code{.sh}
* cmake --build _build --target docs
* \endcode
*
* Optionally include docs in the default build:
*
* \code{.sh}
* cmake -S . -B _build -DMXLIB_BUILD_DOCS=ON
* \endcode
*
* Optional: tune coverage test timeout (default `300` seconds):
*
* \code{.sh}
* cmake -S . -B _build -DMXLIB_COVERAGE_TEST_TIMEOUT=600
* \endcode
*
* Coverage artifacts are written under `_build/`:
*
* - `_build/coverage.info`
* - `_build/coverage_filtered.info`
* - `_build/doc/html/coverage/index.html`
* - `_build/doc/html/index.html`
*
* Clean coverage artifacts:
*
* \code{.sh}
* cmake --build _build --target coverage_clean
* \endcode
*
* Convenience scripts are also available:
*
* - `tests/coverage/make_coverage`
* - `tests/coverage/update_coverage`
*
* @}
*/
26 changes: 26 additions & 0 deletions doc/coverage_report.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/** \addtogroup testing_coverage
* @{
*
* \htmlonly
* <style>
* /* Coverage page: use full available content width (to the right of Doxygen sidebar) */
* .contents,
* .textblock {
* max-width: none !important;
* width: 100% !important;
* }
* .mxlib-coverage-embed {
* display: block;
* width: 100%;
* height: calc(100vh - 220px);
* min-height: 700px;
* border: 1px solid var(--separator-color, #2b3035);
* border-radius: 6px;
* background: var(--page-background-color, #1f2428);
* }
* </style>
* <iframe class="mxlib-coverage-embed" src="coverage/index.html" title="mxlib coverage report"></iframe>
* \endhtmlonly
*
* @}
*/
9 changes: 8 additions & 1 deletion doc/groupdefs.dox
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
* Various miscellaneous utilities
*/


//------------------ error_handling -----------------------

/** \defgroup error_handling_codes Error Codes
Expand Down Expand Up @@ -564,6 +563,14 @@
/** \defgroup mxlib_testing Testing
*/

/** \defgroup testing_building Building Tests
* \ingroup mxlib_testing
*/

/** \defgroup testing_coverage Coverage Report
* \ingroup mxlib_testing
*/

/** \defgroup unit_tests Unit Tests
* \ingroup mxlib_testing
*/
Expand Down
Loading