Skip to content

COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle - #7028

Merged
hjmjohnson merged 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:fix-itkindent-include-cycle
Oct 29, 2026
Merged

hjmjohnson merged 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:fix-itkindent-include-cycle

Conversation

@hjmjohnson

@hjmjohnson hjmjohnson commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Fixes #7025: itkIndent.h fails to compile when it is included before itkMacro.h. This restores @blowekamp's May fix (commits 79f01ca, 4f524e8: itkIndent.h includes no itkMacro.h, so itkMacro.h → itkPrintHelper.h → itkIndent.h cannot loop) and adds a loud error so the cycle cannot come back silently. Supersedes #7026 by @mymonin, whose issue, diagnosis, and include-first regression check this keeps.

  • itkIndent.h includes only the leaf headers ITKCommonExport.h and itkConfigure.h, and marks the legacy New()/Delete() with [[deprecated]] instead of itkLegacyMacro (which lives in itkMacro.h), with a comment saying why.
  • itkPrintHelper.h stops with a message naming the fix if itk::Indent is incomplete when it is reached, which is what including itkMacro.h from itkIndent.h again would cause.
  • itkPrintHelperGTest.cxx includes itkIndent.h first so every build exercises the order from COMP: itkMacro.h must be included before itkIndent.h #7025.

One commit, three files, +15/−2. No forward declarations are needed, so nothing duplicates Indent's operator<< signature.

How the cycle came back
  • 79f01ca/4f524e8 (May 2026) removed #include "itkMacro.h" from itkIndent.h; an #ifndef itkMacro_h #error was tried first and dropped because it broke standalone inclusion in ITKCommonHeaderTest1.
  • 70ddeb8 (Sep 2026) wrapped Indent::New()/Delete() in itkLegacyMacro under #ifndef ITK_LEGACY_REMOVE. Both come from itkMacro.h/itkConfigure.h, so itkIndent.h depended on itkMacro.h again without including it. Most files include itkMacro.h first, so only the ARMBUILD header-test chunk that happened to list itkIndent.h first failed (ENH: Eliminate const_cast from itk::ImageIterator #7021, ENH: Name the series in the non-uniform sampling warning of ImageSeriesReader #7024).
  • [[deprecated]] differs from itkLegacyMacro only in that ITK_LEGACY_SILENT/ITK_LEGACY_TEST no longer silence it for these two members; nothing in ITK calls them, and both are removed under ITK_LEGACY_REMOVE.
  • Including itkMacro.h from itkIndent.h (COMP: Fix missing direct include for macro definition #7026) re-creates the cycle and needs forward declarations of Indent and its operator<< in itkPrintHelper.h. That copy omits ITKCommon_EXPORT, and keeping two declarations in sync is the maintenance cost this PR avoids.
Testing

macOS arm64, Apple clang, Debug, ITKCommon + ITKImageIntensity with MAXIMUM_NUMBER_OF_HEADERS=1 (every header compiled on its own, including itkIndent.h alone):

  • Build: 0 failures, 0 compiler warnings. ctest: 1013/1013 passed.
  • ITK_LEGACY_REMOVE defined: itkIndent.h alone and itkIndent.cxx compile.
  • Include graph (every quoted #include in ITKCommon, include guards ignored): itkIndent.h includes no other ITKCommon header (only the generated, include-free ITKCommonExport.h and itkConfigure.h), so no cycle passes through it. The same check on COMP: Fix missing direct include for macro definition #7026 finds itkIndent.h → itkMacro.h → itkPrintHelper.h → itkIndent.h.
  • Regression check: adding #include "itkMacro.h" back to itkIndent.h makes itkPrintHelperGTest.cxx stop with itkPrintHelper.h:25: error: "itk::Indent incomplete: itkIndent.h must not include itkMacro.h (keep ITKCommonExport.h, itkConfigure.h)".
  • pre-commit run --all-files passes.

Not tested locally: Windows, Linux, Python wrapping.

AI assistance

Claude Code traced the history, wrote the change and the compile checks, and drafted this text at @hjmjohnson's direction; the build and tests above were run locally.

@github-actions github-actions Bot added type:Compiler Compiler support or related warnings type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct area:Core Issues affecting the Core module labels Oct 28, 2026
@hjmjohnson
hjmjohnson force-pushed the fix-itkindent-include-cycle branch from 9680e1d to 374e7f9 Compare October 28, 2026 14:31
@hjmjohnson hjmjohnson changed the title COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle WIP: COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle Oct 28, 2026
@hjmjohnson hjmjohnson changed the title WIP: COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle Oct 28, 2026
@hjmjohnson
hjmjohnson marked this pull request as ready for review October 28, 2026 14:49
@greptile-apps

greptile-apps Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] This PR appears safe to merge.

Summary

This PR makes itkIndent.h work without first including itkMacro.h.

  • itkIndent.h can be included before itkMacro.h without restarting the include cycle.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Macro["itkMacro.h"] --> Print["itkPrintHelper.h"]
  Print --> Indent["itkIndent.h"]
  Indent --> Export["ITKCommonExport.h"]
  Indent --> Configure["itkConfigure.h"]
Loading

Reviews (2) · Last reviewed commit: "COMP: Keep itkIndent.h free of itkMacro...." · Reviewed by Greptile

@hjmjohnson hjmjohnson changed the title COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle WIP: COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle Oct 28, 2026
@hjmjohnson
hjmjohnson marked this pull request as draft October 28, 2026 14:53
itkMacro.h includes itkPrintHelper.h, which includes itkIndent.h, so
itkIndent.h must not depend on itkMacro.h. Since 70ddeb8 it used
itkLegacyMacro and ITK_LEGACY_REMOVE without including the headers that
define them, so a file including itkIndent.h first failed to compile.

Restore the earlier fix (79f01ca, 4f524e8): itkIndent.h includes
only the leaf headers ITKCommonExport.h and itkConfigure.h, and marks
the legacy New() and Delete() with [[deprecated]] instead of
itkLegacyMacro. itkPrintHelper.h now stops with an #error naming the
fix if itk::Indent is incomplete when it is reached, which is what
including itkMacro.h from itkIndent.h again would cause.
itkPrintHelperGTest.cxx includes itkIndent.h first so every build
checks that order.

Closes InsightSoftwareConsortium#7025.

Co-Authored-By: Maxime Monin <318167326+mymonin@users.noreply.github.com>
@hjmjohnson

Copy link
Copy Markdown
Member Author

Sorry for the noise here. 3 failed attempts accidently go co-mingled and pushed and did not represent what I have on my local build. I assumed my local build was the same as the PR incorrectly.

@hjmjohnson
hjmjohnson force-pushed the fix-itkindent-include-cycle branch from 374e7f9 to 3b548bd Compare October 28, 2026 15:00
@github-actions github-actions Bot removed the type:Compiler Compiler support or related warnings label Oct 28, 2026
@hjmjohnson hjmjohnson changed the title WIP: COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle COMP: Restore itkIndent.h without itkMacro.h and fail loudly on the include cycle Oct 28, 2026
@blowekamp

Copy link
Copy Markdown
Member

I don't think adding another header into this complicate dependency order is the correct solution. The additional header will add more complication when similar issues are encountered.

My recommendation is to keep the legacy macro where it is, but change itkIndent to directly use [deprecated note] with a comment why the macro is not used.

... this may have just happened with the latest push?

@hjmjohnson

Copy link
Copy Markdown
Member Author

@blowekamp I had already done that. That was the mistake I made in commingling solutions. You must have reviewed just before the fix. Sorry.

hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Oct 28, 2026
@mymonin

mymonin commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Calling [[deprecated]] directly instead of the macro works as well. Looks good to me.

@hjmjohnson

Copy link
Copy Markdown
Member Author

ITK.Linux.Python on 3b548bd was canceled by Azure at 1h51m while still compiling (no errors in the log; successful runs of this pipeline take 3–4 h), so it is not a result for this change. Re-running it.

@hjmjohnson

Copy link
Copy Markdown
Member Author

/azp run ITK.Linux.Python

@dzenanz dzenanz left a comment

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.

Looks good on a glance.

@dzenanz

dzenanz commented Oct 28, 2026

Copy link
Copy Markdown
Member

Let's merge either this or #7026 today.

I still don't know why the problem started appearing yesterday. #7024 is a minimal change, which does not touch the failing test.

@hjmjohnson

Copy link
Copy Markdown
Member Author

Downstream regression check: no regressions attributable to this PR in the ITK forest testbed (upstream main 3f19582 + this PR's head 3b548bd, macOS arm64, Clang). Every consumer that built before still builds, and no build or test log contains the new #error on the include cycle or any itkLegacyMacro / Indent failure.

Consumer matrix
Target Build Tests
ITK PASS 17/17 ITKCommon (PrintHelper gtests incl. the new include-order test, header test)
elastix PASS 159/164
SimpleITK PASS no tests registered
SphinxExamples PASS 469/565
ANTs PASS 179/179
BRAINSTools PASS 295/416
OpenIGTLink PASS 63/63
Slicer PASS not reported by harness
OpenIGTLinkIO, vtkAddon, IGSIO, PlusLib PASS same shortfalls as prior sweeps
RTK, Cleaver, PerformanceBenchmarking, SimpleITKFilters, TractographyTRX, VkFFTBackend, Impact built ctest skipped, see below

The sub-100% pass counts match earlier sweeps against plain main; none of their failing test logs mention Indent or itkMacro.

Harness caveats (not caused by this PR)
  • The seven remote modules above built cleanly but the harness skipped their ctest because of stale IsotropicWavelets/TubeTK wrapping leftovers in the ITK build tree from a previous session. import itk from that build works (6.0.0). This is a testbed artifact, not a PR effect.
  • SlicerExtensions was interrupted by hand before completion and is untested here.

@hjmjohnson
hjmjohnson marked this pull request as ready for review October 29, 2026 00:29
@hjmjohnson
hjmjohnson merged commit f83647e into InsightSoftwareConsortium:main Oct 29, 2026
18 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Core Issues affecting the Core module type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct

Projects

None yet

Development

Successfully merging this pull request may close these issues.

COMP: itkMacro.h must be included before itkIndent.h

4 participants