Skip to content

DOC: inconsistent dependencies for documentation build#6550

Open
albert-github wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
albert-github:feature/issue_6545
Open

DOC: inconsistent dependencies for documentation build#6550
albert-github wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
albert-github:feature/issue_6545

Conversation

@albert-github

@albert-github albert-github commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Handling the addition and removal of example files for the file Examples.dox

fixes #6545

PR Checklist

@github-actions github-actions Bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Documentation Documentation improvement or change area:Documentation Issues affecting the Documentation module labels Jul 4, 2026
@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR updates the documentation build dependencies for generated example documentation. The main changes are:

  • Collect example source files with GLOB_RECURSE CONFIGURE_DEPENDS.
  • Regenerate Examples.dox when example files are added, removed, or changed.
  • Use the generated Examples.dox path in the Doxygen input list.

Confidence Score: 4/5

The PR is close, but the documentation build rule needs a path fix before merging.

One contained build-rule bug was found in the changed CMake logic. The intended dependency tracking change is localized to documentation generation.

Utilities/Doxygen/CMakeLists.txt

T-Rex T-Rex Logs

What T-Rex did

  • Attempted to configure and build the CMake harness, but cmake and ninja were unavailable, so the run remained blocked.
  • Validated the environment shows CMake and Doxygen are unavailable while Python is available.
  • The smoke harness ran and reported EXIT_CODE: 0 with all assertions passing.
  • Dox example outputs show TrexValidationRemovedExample.java only in before outputs, while TrexValidationAddedExample.py appears in both before and after outputs.
  • Stopped before creating a reproduction harness because CMake remained unavailable.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
Utilities/Doxygen/CMakeLists.txt Adds dependency tracking for example source files when generating Examples.dox, but the custom command declares a different output path than the script writes.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Build as CMake build
participant Glob as EXAMPLES_LIST glob
participant Target as ITKDoxygenExamplesDox
participant Script as GenerateExamplesDox.cmake
participant Out as Documentation/Doxygen/Examples.dox
Build->>Glob: "collect Examples/*.cxx, *.py, *.java"
Glob-->>Target: file dependencies
Target->>Script: "run with OUTPUT_FILE=${ITK_EXAMPLES}"
Script->>Out: generate Examples.dox
Target-->>Build: "documentation input uses ${ITK_EXAMPLES}"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Build as CMake build
participant Glob as EXAMPLES_LIST glob
participant Target as ITKDoxygenExamplesDox
participant Script as GenerateExamplesDox.cmake
participant Out as Documentation/Doxygen/Examples.dox
Build->>Glob: "collect Examples/*.cxx, *.py, *.java"
Glob-->>Target: file dependencies
Target->>Script: "run with OUTPUT_FILE=${ITK_EXAMPLES}"
Script->>Out: generate Examples.dox
Target-->>Build: "documentation input uses ${ITK_EXAMPLES}"
Loading

Reviews (1): Last reviewed commit: "DOC: inconsistent dependencies for docum..." | Re-trigger Greptile

Comment thread Utilities/Doxygen/CMakeLists.txt Outdated
Comment on lines 175 to 194
add_custom_command(
OUTPUT
"${ITK_BINARY_DIR}/Documentation/Doxygen/Examples.dox"
Examples.dox
COMMAND
${CMAKE_COMMAND} -D "PROJECT_SOURCE_DIR:PATH=${ITK_SOURCE_DIR}" -D
"OUTPUT_FILE:PATH=${ITK_BINARY_DIR}/Documentation/Doxygen/Examples.dox" -P
"OUTPUT_FILE:PATH=${ITK_EXAMPLES}" -P
"${ITK_SOURCE_DIR}/Utilities/Doxygen/GenerateExamplesDox.cmake"
WORKING_DIRECTORY "${ITK_SOURCE_DIR}/Examples"
#WORKING_DIRECTORY "${ITK_SOURCE_DIR}/Examples"
WORKING_DIRECTORY ${ITK_BINARY_DIR}/Documentation/Doxygen
DEPENDS
"${ITK_SOURCE_DIR}/Examples"
${EXAMPLES_LIST}
"${ITK_SOURCE_DIR}/Utilities/Doxygen/GenerateExamplesDox.cmake"
)
set_source_files_properties(${ITK_EXAMPLES} PROPERTIES GENERATED 1)
add_custom_target(
ITKDoxygenExamplesDox
ITKDoxygenExamplesDox
ALL
DEPENDS
"${ITK_BINARY_DIR}/Documentation/Doxygen/Examples.dox"
Examples.dox
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Match generated output
OUTPUT Examples.dox and the target dependency are relative to this CMake directory’s binary tree, but the script writes to ${ITK_EXAMPLES} under Documentation/Doxygen. With Ninja/Make, the declared output is never produced, so the custom command remains out of date or fails after generation even though the intended file exists.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@albert-github Can you please address this greptile concern?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look into it, but it will take a bit over a week before I have time to really look into it (and I don't have ninja).

@hjmjohnson hjmjohnson Jul 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@albert-github

Greptile is right, and I confirmed with a minimal Ninja reproduction that this fails on a fresh build tree. Two problems:

  1. A relative OUTPUT Examples.dox resolves to ${ITK_BINARY_DIR}/Utilities/Doxygen/Examples.dox (this directory's binary dir), while the script writes to ${ITK_EXAMPLES} under Documentation/Doxygen — so the declared output is never produced.
  2. Ninja does not create WORKING_DIRECTORY, so cd .../Documentation/Doxygen fails before the script even runs. Since GenerateExamplesDox.cmake uses only absolute paths, the WORKING_DIRECTORY can be dropped entirely.

Suggested replacement (verified to build and be a no-op on rebuild with Ninja):

add_custom_command(
  OUTPUT
    ${ITK_EXAMPLES}
  COMMAND
    ${CMAKE_COMMAND} -D "PROJECT_SOURCE_DIR:PATH=${ITK_SOURCE_DIR}" -D
    "OUTPUT_FILE:PATH=${ITK_EXAMPLES}" -P
    "${ITK_SOURCE_DIR}/Utilities/Doxygen/GenerateExamplesDox.cmake"
  DEPENDS
    ${EXAMPLES_LIST}
    "${ITK_SOURCE_DIR}/Utilities/Doxygen/GenerateExamplesDox.cmake"
)
add_custom_target(ITKDoxygenExamplesDox ALL DEPENDS ${ITK_EXAMPLES})

The set_source_files_properties(... GENERATED 1) block can also be removed — add_custom_command outputs are automatically marked GENERATED — and please delete the commented-out #WORKING_DIRECTORY line rather than keeping it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hjmjohnson

Thanks for looking into the problem.

With the given change it looks like (for me with nmake):

  • it runs with a clean build
  • it runs also when compared to previous build an example file is added
  • It looks like there is a problem when a file is removed from the list of examples.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@albert-github Thanks for testing and for reporting the removal case — it is a real problem, and it is not specific to nmake. I reproduced it with Ninja and tracked down the cause: it is caused by my suggested patch, and the reason the current code appears to handle removal is the very bug Greptile flagged. Both are the same finding. Patch below resolves all of it; verified locally on a real ITK documentation build.

Why removal appeared to work before, and breaks with my patch

The current OUTPUT Examples.dox is relative, so it resolves to ${ITK_BINARY_DIR}/Utilities/Doxygen/Examples.dox, while the script writes to ${ITK_EXAMPLES} under Documentation/Doxygen. The declared output is therefore never created, so the command is permanently out of date and reruns on every build — which incidentally always picks up removals. That is why removal looks fine today: it is a side effect of the path bug, not a working dependency.

Once the path is corrected, the command is properly up to date, and the real gap shows: CONFIGURE_DEPENDS does its job (Ninja prints GLOB mismatch! The following files were removed: and CMake re-runs, so EXAMPLES_LIST is correct), but that only updates the dependency list. Deleting a dependency cannot make an existing output out of date — Examples.dox is newer than every remaining input and the command line is unchanged, so nothing reruns and the deleted example stays listed forever.

The fix is to depend on something whose content changes when the glob does: a stamp file holding the list. file(CONFIGURE) is write-if-different, so it does not reintroduce rebuild-every-time.

Patch (replaces the block from the set(ITK_EXAMPLES ...) line through add_custom_target)
  set(ITK_EXAMPLES ${ITK_BINARY_DIR}/Documentation/Doxygen/Examples.dox)

  # Removing an example changes only EXAMPLES_LIST, which cannot make
  # Examples.dox out of date; depend on a stamp holding the list itself so a
  # deletion is seen. file(CONFIGURE) rewrites only when the content differs.
  set(
    ITK_EXAMPLES_LIST_STAMP
    ${ITK_BINARY_DIR}/Documentation/Doxygen/ExamplesList.txt
  )
  string(REPLACE ";" "\n" ITK_EXAMPLES_LIST_CONTENT "${EXAMPLES_LIST}")
  file(
    CONFIGURE
    OUTPUT ${ITK_EXAMPLES_LIST_STAMP}
    CONTENT "${ITK_EXAMPLES_LIST_CONTENT}\n"
  )

  # Custom command to generate a examples page which include all ITK examples
  add_custom_command(
    OUTPUT
      ${ITK_EXAMPLES}
    COMMAND
      ${CMAKE_COMMAND} -D "PROJECT_SOURCE_DIR:PATH=${ITK_SOURCE_DIR}" -D
      "OUTPUT_FILE:PATH=${ITK_EXAMPLES}" -P
      "${ITK_SOURCE_DIR}/Utilities/Doxygen/GenerateExamplesDox.cmake"
    DEPENDS
      ${EXAMPLES_LIST}
      ${ITK_EXAMPLES_LIST_STAMP}
      "${ITK_SOURCE_DIR}/Utilities/Doxygen/GenerateExamplesDox.cmake"
  )
  add_custom_target(ITKDoxygenExamplesDox ALL DEPENDS ${ITK_EXAMPLES})

Relative to what is pushed, this: makes OUTPUT and the target dependency absolute; drops WORKING_DIRECTORY (Ninja does not create it, and GenerateExamplesDox.cmake uses only absolute paths) together with the commented-out line above it; drops set_source_files_properties(... GENERATED 1) (add_custom_command outputs are marked GENERATED automatically); and adds the list stamp.

The formatting above is already gersemi-clean, so it should pass the style hook as-is.

Local testing

Real ITK tree, -DITK_BUILD_DOCUMENTATION=ON, CMake 4.2.1 / Ninja 1.13.2 / Linux. A = this PR as pushed, B = my earlier suggestion, C = the patch above.

scenario A (pushed) B (earlier suggestion) C (patch above)
clean build 293 listed ✅ 293 ✅ 293 ✅
add an example 294 ✅ 294 ✅ 294 ✅
remove an example 292 ✅ 293 ❌ stale 292 ✅
no-op rebuild ❌ regenerates every build ✅ no work to do ✅ no work to do

For C also checked: removing a tracked example (Examples/Filtering/BinaryThresholdImageFilter.cxx) drops it from Examples.dox and restoring it brings it back; a forced reconfigure with no source change leaves the stamp mtime byte-identical and the build still reports no work to do. pre-commit run --all-files exits 0.

I have not verified this on nmake — since you do not have Ninja and I do not have nmake, it would be worth a quick check on your side that the removal case now passes there too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hjmjohnson

Thanks for the new patch this indeed looks like to work prpoerly.

Comment thread Utilities/Doxygen/CMakeLists.txt
@dzenanz

dzenanz commented Jul 17, 2026

Copy link
Copy Markdown
Member

Preferably squash into one commit, either upon merge, or before merge.

@albert-github

Copy link
Copy Markdown
Contributor Author

Indeed should be / can be squashed.
As I don't know how to do the squashing, better to do it upon merge.

Handling the addition and removal of example files for the file `Examples.dox`

Fixes InsightSoftwareConsortium#6545.
@dzenanz
dzenanz force-pushed the feature/issue_6545 branch from de895e4 to 3861a6c Compare July 17, 2026 18:35
@dzenanz

dzenanz commented Jul 17, 2026

Copy link
Copy Markdown
Member

I squashed and rebased.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Documentation Issues affecting the Documentation module type:Documentation Documentation improvement or change type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DOC: inconsistent dependencies for documentation build

3 participants