Skip to content

Commit 2068f2e

Browse files
authored
Merge pull request #31 from stlab:execution-toolkit-integration
Add consumer documentation extensions and runtime DLL helper
2 parents b5273fd + e7494f7 commit 2068f2e

17 files changed

Lines changed: 353 additions & 27 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ jobs:
2929
- name: Run target type tests
3030
run: cmake -P tests/setup/test_target_type.cmake
3131

32+
- name: Run custom executable runtime deployment tests
33+
run: cmake -P tests/setup/test_runtime_dlls.cmake
34+
3235
- name: Run setup.cmake version resolution test
3336
run: cmake -P tests/setup/test_setup_version_resolution.cmake
3437

@@ -44,6 +47,9 @@ jobs:
4447
- name: Run target type tests
4548
run: cmake -P tests/setup/test_target_type.cmake
4649

50+
- name: Run custom executable runtime deployment tests
51+
run: cmake -P tests/setup/test_runtime_dlls.cmake
52+
4753
- name: Run nested static and shared installation round trips
4854
run: cmake -P tests/install/test_nested_install.cmake
4955

@@ -165,6 +171,13 @@ jobs:
165171
# [DEPENDENCY] https://github.com/actions/checkout/releases
166172
- uses: actions/checkout@v7
167173

174+
- name: Install Doxygen
175+
# [DEPENDENCY] https://github.com/ssciwr/doxygen-install/releases
176+
uses: ssciwr/doxygen-install@fa3e94d34131d3990b6b8ba939ab982964aa3758
177+
178+
- name: Test documentation configuration and rendered output
179+
run: cmake -P tests/docs/test_docs.cmake
180+
168181
- name: Check README examples
169182
run: |
170183
# Extract and validate code blocks from README

‎.scout/scout.config.yaml‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
# ignore / dampen / boost / tune overrides; defaults for
66
# repository/markdown/ranking/index/projects are filled in at load time.
77
ignore:
8-
- '**/CHANGELOG.md'
9-
- '**/CHANGELOG*'
10-
- '**/CHANGES.md'
11-
- '**/HISTORY.md'
8+
- "**/CHANGELOG.md"
9+
- "**/CHANGELOG*"
10+
- "**/CHANGES.md"
11+
- "**/HISTORY.md"
12+
- .claude/worktrees/
1213

1314
dampen:
1415
- factor: 0.3
1516
patterns:
16-
- '**/package.json'
17+
- "**/package.json"

‎CLAUDE.md‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,20 @@ Two ways consumers use this repo:
1212

1313
## Commands
1414

15-
Run cpp-library's own test suite (pure CMake scripts, no C++ compilation involved):
15+
Run cpp-library's tests through CMake scripts. Integration fixtures require a
16+
C++ compiler and Ninja; documentation rendering also requires Doxygen:
1617

1718
```bash
1819
cmake -P tests/install/CMakeLists.txt # dependency mapping/merging unit tests
1920
cmake -P tests/install/test_provider_merge.cmake # dependency provider merge tests
2021
cmake -P tests/setup/test_setup_version_resolution.cmake # setup.cmake version-resolution integration test
22+
cmake -P tests/setup/test_runtime_dlls.cmake # custom target DLL deployment; requires compiler and Ninja
23+
cmake -P tests/docs/test_docs.cmake # docs extensions and rendering; requires Doxygen and Ninja
2124
```
2225

23-
These are the same commands CI (`.github/workflows/ci.yml`, job `unit-tests`) runs. There is no build step for cpp-library itself — `cmake -P` executes the scripts directly.
26+
CI (`.github/workflows/ci.yml`) runs these scripts in its unit-test, Windows
27+
package, and documentation jobs. There is no library build step for cpp-library
28+
itself; integration scripts configure and build their own consumer fixtures.
2429

2530
CI also runs an `integration-tests` job that generates a throwaway consumer project, configures/builds/installs it against this repo via `CPMAddPackage(... SOURCE_DIR ...)`, then verifies `find_package()` works against the installed package — this is the best reference for the full round-trip a downstream project goes through.
2631

@@ -45,7 +50,7 @@ or pin to a specific commit: `CPMAddPackage("gh:stlab/cpp-library#<commit-sha>")
4550
- **`cpp-library-dependency-provider.cmake`** — implements the CMake dependency-provider callback (`SET_DEPENDENCY_PROVIDER`) that intercepts every `find_package()`/`FetchContent_MakeAvailable()` call to record the exact package/version/components used, so `Config.cmake` can regenerate accurate `find_dependency()` calls at install time. State is stored in `GLOBAL` properties (`_CPP_LIBRARY_TRACKED_DEP_*`, `_CPP_LIBRARY_PKG_KEYS`, etc.) — there's no other persistence mechanism, so tests reset these properties between cases (see `tests/install/CMakeLists.txt`).
4651
- **`cpp-library-docs.cmake`** — Doxygen + doxygen-awesome-css target (`docs`).
4752
- **`cpp-library-ci.cmake`** — generates `.github/workflows/ci.yml` for the *consumer* project from `templates/.github/workflows/ci.yml.in`, substituting the package name.
48-
- **`cpp-library-testing.cmake`** — thin backward-compat wrapper; real test/example executable logic lives in `_cpp_library_setup_executables()` in `cpp-library.cmake`.
53+
- **`cpp-library-testing.cmake`** — public `cpp_library_copy_runtime_dlls()` helper and backward-compatibility `_cpp_library_setup_testing()` wrapper; test/example executable creation lives in `_cpp_library_setup_executables()` in `cpp-library.cmake`.
4954

5055
### Key control flow
5156

‎README.md‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ cpp_library_setup(
361361
[EXAMPLES example_list] # Example source files to build (e.g., "example.cpp example_fail.cpp")
362362
[TESTS test_list] # Test source files to build (e.g., "tests.cpp")
363363
[DOCS_EXCLUDE_SYMBOLS symbols] # Symbols to exclude from docs
364+
[DOCS_INPUTS input_list] # Additional documentation files/directories
365+
[DOCS_OPTIONS setting_list] # Additive single-line Doxygen assignments
364366
[REQUIRES_CPP_VERSION 17|20|23] # C++ version (default: 17)
365367
[INSTALL_OPTION option_name] # Independent installation control (default: uppercase NAMESPACE_INSTALL)
366368
)
@@ -374,6 +376,57 @@ cpp_library_setup(
374376
- Installation is controlled by `INSTALL_OPTION`, or the uppercase `${NAMESPACE}_INSTALL` option
375377
when omitted. Options default to `PROJECT_IS_TOP_LEVEL`.
376378

379+
### Documentation configuration
380+
381+
Keep the toolkit's Doxyfile template instead of copying it into your project.
382+
`DOCS_INPUTS` adds files or directories to the default `include` input. Relative
383+
paths are resolved against the directory calling `cpp_library_setup`; absolute
384+
paths and paths containing spaces are supported. Missing inputs fail configuration.
385+
386+
`DOCS_OPTIONS` applies project-specific Doxygen assignments after the shared
387+
template. Each quoted CMake argument must be a single `TAG = value` or
388+
`TAG += value` assignment, with Doxygen quoting inside the value when needed.
389+
Use spaces, not CMake semicolons, to separate Doxygen list values. The toolkit
390+
validates assignment syntax and rejects line-continuation backslashes, including
391+
those followed by whitespace; Doxygen validates tag names and values. Settings
392+
are literal, not `configure_file` templates: use `${...}` for CMake variables.
393+
394+
```cmake
395+
cpp_library_setup(
396+
DESCRIPTION "My library"
397+
NAMESPACE mylib
398+
HEADERS api.hpp
399+
DOCS_INPUTS docs/doxygen "${PROJECT_BINARY_DIR}/generated docs"
400+
DOCS_EXCLUDE_SYMBOLS "mylib::detail"
401+
DOCS_OPTIONS
402+
"WARN_IF_UNDOCUMENTED = NO"
403+
"INCLUDE_PATH = \"${PROJECT_BINARY_DIR}/include\""
404+
"MACRO_EXPANSION = YES"
405+
"PREDEFINED = MYLIB_API= MYLIB_NAMESPACE_BEGIN()= MYLIB_NAMESPACE_END()="
406+
)
407+
```
408+
409+
Existing `docs/Doxyfile` overrides remain supported. Additional inputs and options
410+
are applied after that configuration too, but a full override does not inherit
411+
future toolkit-template changes. Prefer the shared template with only the
412+
project-specific deltas above. Documentation is configured only for top-level
413+
projects with `BUILD_DOCS` enabled.
414+
415+
### `cpp_library_copy_runtime_dlls`
416+
417+
```cmake
418+
add_executable(custom-test main.cpp support.cpp)
419+
target_link_libraries(custom-test PRIVATE mylib::my-library)
420+
cpp_library_copy_runtime_dlls(custom-test)
421+
```
422+
423+
Call this helper in the directory that created the target. On Windows, it deploys
424+
`TARGET_RUNTIME_DLLS` beside the target after building, including transitive
425+
runtime DLLs. Static targets with no runtime DLLs require no copy; on other
426+
platforms the helper does nothing. It uses CMake 3.24-compatible copy operations
427+
and handles DLLs already in the destination. Toolkit-created test/example
428+
executables use the same helper automatically.
429+
377430
### Target Naming
378431

379432
Use the component name as your project name, and specify the organizational namespace separately:

‎cmake/cpp-library-docs.cmake‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,30 @@ function(_cpp_library_setup_docs)
1313
)
1414
set(multiValueArgs
1515
DOCS_EXCLUDE_SYMBOLS
16+
DOCS_INPUTS
17+
DOCS_OPTIONS
1618
)
1719

1820
cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
1921

22+
set(docs_extensions "")
23+
foreach(input IN LISTS ARG_DOCS_INPUTS)
24+
get_filename_component(input "${input}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
25+
if(NOT EXISTS "${input}")
26+
message(FATAL_ERROR "cpp-library: Documentation input does not exist: ${input}")
27+
endif()
28+
string(REPLACE "\"" "\\\"" input "${input}")
29+
string(APPEND docs_extensions "INPUT += \"${input}\"\n")
30+
endforeach()
31+
foreach(option IN LISTS ARG_DOCS_OPTIONS)
32+
if(NOT option MATCHES "^[A-Z][A-Z0-9_]*[ \t]*\\+?=[^\r\n]*$"
33+
OR option MATCHES "\\\\[ \t]*$")
34+
message(FATAL_ERROR
35+
"cpp-library: DOCS_OPTIONS requires single-line Doxygen assignments: ${option}")
36+
endif()
37+
string(APPEND docs_extensions "${option}\n")
38+
endforeach()
39+
2040
find_package(Doxygen REQUIRED)
2141

2242
# Download doxygen-awesome-css theme via CPM
@@ -60,6 +80,10 @@ function(_cpp_library_setup_docs)
6080
else()
6181
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
6282
endif()
83+
if(NOT docs_extensions STREQUAL "")
84+
file(APPEND "${DOXYFILE_OUT}"
85+
"\n# Project documentation settings supplied through cpp_library_setup.\n${docs_extensions}")
86+
endif()
6387

6488
# Add custom target for documentation with proper stderr capture
6589
if(WIN32)

‎cmake/cpp-library-testing.cmake‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
# SPDX-License-Identifier: BSL-1.0
22
#
3-
# cpp-library-testing.cmake - Testing setup with doctest
3+
# cpp-library-testing.cmake - Runtime DLL deployment and testing compatibility
44
#
5-
# Note: Testing logic has been consolidated into the main cpp-library.cmake file
6-
# This file is kept for backward compatibility but the actual implementation
7-
# is now in the _cpp_library_setup_executables function.
5+
# Provides cpp_library_copy_runtime_dlls for custom and toolkit-created executables.
6+
# _cpp_library_setup_testing delegates to _cpp_library_setup_executables for compatibility.
7+
8+
# Deploys runtime DLLs beside a custom target on Windows; empty lists need no copy.
9+
# Call in the directory that created the target, as required by POST_BUILD commands.
10+
function(cpp_library_copy_runtime_dlls target)
11+
if(NOT TARGET "${target}")
12+
message(FATAL_ERROR "cpp_library_copy_runtime_dlls: Target does not exist: ${target}")
13+
endif()
14+
if(WIN32)
15+
add_custom_command(TARGET ${target} POST_BUILD
16+
COMMAND "${CMAKE_COMMAND}"
17+
"-DCPP_LIBRARY_RUNTIME_DLLS=$<TARGET_RUNTIME_DLLS:${target}>"
18+
"-DCPP_LIBRARY_RUNTIME_DESTINATION=$<TARGET_FILE_DIR:${target}>"
19+
-P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/cpp-library-copy-runtime-dlls.cmake"
20+
VERBATIM)
21+
endif()
22+
endfunction()
823

924
# Delegates to _cpp_library_setup_executables for backward compatibility.
1025
# - Postcondition: test executables configured via _cpp_library_setup_executables

‎cpp-library.cmake‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,7 @@ function(_cpp_library_setup_executables)
134134
add_executable(${executable_base} "${source_dir}/${executable}")
135135
target_link_libraries(${executable_base} PRIVATE ${ARG_NAMESPACE}::${CLEAN_NAME} doctest::doctest)
136136

137-
if(WIN32)
138-
# A script handles empty DLL lists without requiring newer copy commands.
139-
add_custom_command(TARGET ${executable_base} POST_BUILD
140-
COMMAND "${CMAKE_COMMAND}"
141-
"-DCPP_LIBRARY_RUNTIME_DLLS=$<TARGET_RUNTIME_DLLS:${executable_base}>"
142-
"-DCPP_LIBRARY_RUNTIME_DESTINATION=$<TARGET_FILE_DIR:${executable_base}>"
143-
-P "${CPP_LIBRARY_ROOT}/cmake/cpp-library-copy-runtime-dlls.cmake"
144-
VERBATIM)
145-
endif()
137+
cpp_library_copy_runtime_dlls(${executable_base})
146138

147139
# Register as CTest test
148140
add_test(NAME ${executable_base} COMMAND ${executable_base})
@@ -182,13 +174,20 @@ function(cpp_library_setup)
182174
EXAMPLES # Example source files to build (e.g., "example.cpp example_fail.cpp")
183175
TESTS # Test source files to build (e.g., "tests.cpp")
184176
DOCS_EXCLUDE_SYMBOLS # Symbols to exclude from docs
177+
DOCS_INPUTS # Additional documentation files or directories
178+
DOCS_OPTIONS # Single-line Doxygen assignments applied after the template
185179
)
186180

187181
cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
188182

189183
if("INSTALL_OPTION" IN_LIST ARG_KEYWORDS_MISSING_VALUES)
190184
message(FATAL_ERROR "cpp_library_setup: INSTALL_OPTION requires a value")
191185
endif()
186+
foreach(keyword DOCS_INPUTS DOCS_OPTIONS)
187+
if(keyword IN_LIST ARG_KEYWORDS_MISSING_VALUES)
188+
message(FATAL_ERROR "cpp_library_setup: ${keyword} requires a value")
189+
endif()
190+
endforeach()
192191
set(install_args)
193192
if(DEFINED ARG_INSTALL_OPTION)
194193
list(APPEND install_args INSTALL_OPTION "${ARG_INSTALL_OPTION}")
@@ -333,6 +332,8 @@ function(cpp_library_setup)
333332
VERSION "${ARG_VERSION}"
334333
DESCRIPTION "${ARG_DESCRIPTION}"
335334
DOCS_EXCLUDE_SYMBOLS "${ARG_DOCS_EXCLUDE_SYMBOLS}"
335+
DOCS_INPUTS "${ARG_DOCS_INPUTS}"
336+
DOCS_OPTIONS "${ARG_DOCS_OPTIONS}"
336337
)
337338
endif()
338339

‎templates/Doxyfile.in‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@
44
PROJECT_NAME = "@PROJECT_NAME@"
55
PROJECT_BRIEF = "@PROJECT_BRIEF@"
66
PROJECT_NUMBER = @PROJECT_VERSION@
7-
OUTPUT_DIRECTORY = @OUTPUT_DIR@
7+
OUTPUT_DIRECTORY = "@OUTPUT_DIR@"
88
GENERATE_LATEX = NO
99
QUIET = YES
1010
WARN_IF_UNDOCUMENTED = YES
11-
INPUT = @INPUT_DIR@
11+
INPUT = "@INPUT_DIR@"
1212
RECURSIVE = YES
1313
EXCLUDE_SYMBOLS = @EXCLUDE_SYMBOLS@
14-
EXAMPLE_PATH = @EXAMPLES_PATH@
14+
EXAMPLE_PATH = "@EXAMPLES_PATH@"
1515
HIDE_UNDOC_NAMESPACES = NO
16-
HTML_EXTRA_STYLESHEET = @AWESOME_CSS_PATH@/doxygen-awesome.css \
17-
@AWESOME_CSS_PATH@/doxygen-awesome-sidebar-only.css \
18-
@CPP_LIBRARY_ROOT@/templates/custom.css
16+
HTML_EXTRA_STYLESHEET = "@AWESOME_CSS_PATH@/doxygen-awesome.css" \
17+
"@AWESOME_CSS_PATH@/doxygen-awesome-sidebar-only.css" \
18+
"@CPP_LIBRARY_ROOT@/templates/custom.css"
1919
HTML_COLORSTYLE = LIGHT
2020
GENERATE_TREEVIEW = YES
2121
DISABLE_INDEX = NO

‎tests/docs/fixtures/CMakeLists.txt‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
cmake_minimum_required(VERSION 3.24)
2+
project(docs-fixture LANGUAGES CXX)
3+
include("${TOOLKIT_SOURCE}/cpp-library.cmake")
4+
set(CPP_LIBRARY_VERSION 1.2.3)
5+
set(FIXTURE_INSTALL OFF CACHE BOOL "")
6+
set(BUILD_DOCS ON)
7+
8+
# Replace only the network theme download; exercise real configuration and Doxygen.
9+
function(CPMAddPackage)
10+
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/theme")
11+
foreach(stylesheet doxygen-awesome.css doxygen-awesome-sidebar-only.css)
12+
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/theme/${stylesheet}" "")
13+
endforeach()
14+
set(doxygen-awesome-css_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/theme" PARENT_SCOPE)
15+
endfunction()
16+
17+
set(docs_args)
18+
if(CASE STREQUAL "extended")
19+
list(APPEND docs_args
20+
DOCS_INPUTS "extra docs" "${CMAKE_CURRENT_SOURCE_DIR}/absolute docs/group.dox"
21+
DOCS_OPTIONS
22+
"PROJECT_BRIEF = \"Customized documentation\""
23+
"WARN_IF_UNDOCUMENTED = NO"
24+
[=[PREDEFINED = "FIXTURE_PATH=C:\\docs\\"]=]
25+
"EXCLUDE_SYMBOLS += fixture::extra"
26+
DOCS_EXCLUDE_SYMBOLS "fixture::hidden")
27+
elseif(CASE STREQUAL "missing-input")
28+
list(APPEND docs_args DOCS_INPUTS "missing docs")
29+
elseif(CASE STREQUAL "malformed-option")
30+
list(APPEND docs_args DOCS_OPTIONS "not a Doxygen assignment")
31+
elseif(CASE STREQUAL "malformed-terminal-continuation-option")
32+
list(APPEND docs_args DOCS_OPTIONS [=[PREDEFINED = A= \]=])
33+
elseif(CASE STREQUAL "malformed-continuation-option")
34+
list(APPEND docs_args DOCS_OPTIONS
35+
[=[PREDEFINED = A= \ ]=]
36+
"WARN_IF_UNDOCUMENTED = NO")
37+
elseif(CASE STREQUAL "multiline-option")
38+
list(APPEND docs_args DOCS_OPTIONS "QUIET = YES\nGENERATE_XML = YES")
39+
elseif(CASE STREQUAL "missing-input-value")
40+
list(APPEND docs_args DOCS_INPUTS)
41+
elseif(CASE STREQUAL "missing-option-value")
42+
list(APPEND docs_args DOCS_OPTIONS)
43+
elseif(CASE STREQUAL "custom")
44+
file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/docs")
45+
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile"
46+
"PROJECT_NAME = \"Legacy configuration\"\n"
47+
"INPUT = \"@INPUT_DIR@\"\n"
48+
"OUTPUT_DIRECTORY = \"@OUTPUT_DIR@\"\n"
49+
"GENERATE_LATEX = NO\nQUIET = YES\nWARN_AS_ERROR = YES\n")
50+
list(APPEND docs_args DOCS_INPUTS "extra docs"
51+
DOCS_OPTIONS "PROJECT_BRIEF = \"Customized documentation\"")
52+
endif()
53+
54+
cpp_library_setup(
55+
DESCRIPTION "Documentation fixture"
56+
NAMESPACE fixture
57+
INSTALL_OPTION FIXTURE_INSTALL
58+
HEADERS api.hpp
59+
${docs_args})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/** @defgroup extra_group Absolute fixture group
2+
* @brief This group comes from an absolute input file.
3+
*/

0 commit comments

Comments
 (0)