Skip to content

Comments

Add #undef support with two-pass headertree discovery#6

Merged
DrGeoff merged 5 commits intomasterfrom
headertree-hunter-agreement
Feb 16, 2026
Merged

Add #undef support with two-pass headertree discovery#6
DrGeoff merged 5 commits intomasterfrom
headertree-hunter-agreement

Conversation

@DrGeoff
Copy link
Owner

@DrGeoff DrGeoff commented Feb 16, 2026

Summary

  • Add #undef tracking to the preprocessing cache so macros cleaned up via #undef no longer silently persist and break subsequent conditional compilation
  • Add two-pass macro convergence to ct-headertree (matching hunter's existing approach) so both tools agree on conditionally-included headers

Cache design: input-independent file_undefs

The naive approach of adding 'undef' to _extract_conditional_macros works but is semantically wrong -- #undef does not affect active lines, it only mutates output macro state. This demotes files from invariant to variant caching unnecessarily, causing extra cache misses on codebases with #undef directives.

Instead, file_undefs is computed from active #undef directive targets (input-independent) rather than diffing input vs output macro state (input-dependent). MacroState.without_keys() handles the intersection with the caller's variable macros at cache-hit time, so invariant caching is preserved for files that only have #undef without conditionals.

Supporting changes:

  • Add undef_targets static field to FileAnalysisResult
  • Add without_keys() method to MacroState
  • Add leaked-macro-pkg.pc test fixture and pkgconfig_env to undef tests

Test plan

  • test_undef_bug_sample validates #undef is correctly processed across file boundaries
  • test_headertree_hunter_agreement validates headertree and hunter agree on all sample cases (empty_macro_bug, undef_bug, macro_state_dependency)
  • test_preprocessing_cache validates cache behavior with undefs
  • Full test suite passes (420 passed, 2 skipped)

Invariant cache now recomputes updated_macros with current input state
instead of using stale cached state. Pass 2 only clears variant caches,
preserving invariant results which are truly macro-independent.
This is due to the different methods used to determine includes.
# Conflicts:
#	src/compiletools/headerdeps.py
#	src/compiletools/magicflags.py
#	src/compiletools/preprocessing_cache.py
- Track file_undefs in preprocessing cache for correct macro state
  propagation across files (#undef no longer silently ignored)
- Add two-pass macro convergence to ct-headertree (matching hunter)
  so both tools agree on conditionally-included headers
- Make file_undefs computation input-independent (active #undef
  directive targets) to preserve invariant caching for files with
  only #undef and no conditionals
- Add undef_targets static field to FileAnalysisResult
- Add leaked-macro-pkg.pc fixture and pkgconfig_env to undef tests
@DrGeoff
Copy link
Owner Author

DrGeoff commented Feb 16, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@DrGeoff DrGeoff merged commit 4c0cab4 into master Feb 16, 2026
5 checks passed
@DrGeoff DrGeoff deleted the headertree-hunter-agreement branch February 16, 2026 02:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant