Skip to content

fix: limit generated source placeholders to the prepare-time scan - #779

Draft
julixian wants to merge 2 commits into
mcpp-community:mainfrom
julixian:fix/source-action-placeholder-lifetime
Draft

julixian wants to merge 2 commits into
mcpp-community:mainfrom
julixian:fix/source-action-placeholder-lifetime

Conversation

@julixian

@julixian julixian commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Clearing a workspace member's target while retaining the workspace Ninja log can skip a source-generation action: prepare creates a newer scan placeholder at the missing output path, and Ninja treats it as an up-to-date generated source. The build then compiles the placeholder instead of the generator output.

Prepare now owns only the placeholders it creates. It removes them after source scanning, before final planning and Ninja's incremental checks. Scope cleanup also removes them when prepare fails. Existing outputs, including legitimately empty sources, are preserved.

Closes #778.

Criteria

Validated on Windows x64 with MSVC 14.51.36231, Windows SDK 10.0.26100.0 and LLVM 22.1.8:

  • Self-host build: mcpp build --toolchain llvm@22.1.8 using bootstrap 2026.10.5.3 succeeded. All following binary tests used that freshly built executable.
  • test --toolchain llvm@22.1.8: 147 test programs passed, 0 failed; platform-specific cases skipped according to their existing gates.
  • test -p buildmcpp --toolchain llvm@22.1.8: all 3 test programs passed, including the 3 new ActionPlaceholders cases. Two existing symlink cases skipped because this host lacks directory-symlink privileges.
  • tests/e2e/890_source_placeholders_do_not_hide_missing_outputs.sh: the released 2026.10.5.3 binary fails after clearing the member output directory with an undefined generated_value() symbol. The fresh binary passes: cold build, warm build, re-prepare without regeneration, member-only cleanup, configure-only followed by build, and generated module-interface cleanup.
  • tests/e2e/01_help_and_version.sh passed with the fresh binary.
  • The full E2E suite and Linux/macOS validation are left to the PR CI; they have not been run locally.

Intersections

New rule or feature Invariant it crosses Test at the crossing
Prepare owns temporary source outputs Scanning needs translation units and declared module providers; companion headers must not become scan placeholders ActionPlaceholders.MissingSourcesExistOnlyDuringScanning, ModuleDeclarationsAreAvailableUntilScopeExit, and e2e 890's module-interface builds
Placeholders disappear after scanning Missing generator outputs must trigger their actions without invalidating existing outputs or rerunning warm generators ActionPlaceholders.ExistingOutputsIncludingEmptySourcesArePreserved and e2e 890's member-clean and warm-build checks
Scope cleanup covers unsuccessful prepare Failed and configure-only planning must not leave fake generator outputs for later builds The module scope-unwinding unit case and e2e 890's configure-only check

Compatibility

No CLI, manifest or build-program protocol changes. Missing generated translation units are regenerated even when an older Ninja record survives. Existing generated files retain their contents and timestamps. The engine's internal prepare_actions helper takes an explicit placeholder owner.

Checks before merging

  • bash .github/tools/check_docs_style.sh, check_docs_structure.sh and check_version_pins.sh pass. Python-backed documentation checks ran with PYTHONUTF8=1 on this Windows host.
  • python3 .github/tools/check_workflow_assertions.py passes: 22 workflows, 0 problems.
  • No commit on the branch carries an attribution trailer: git log origin/main..HEAD -i --grep='Co-Authored-By' prints nothing.
  • If squash merging, provide an explicit subject and body rather than GitHub's generated commit aggregation.

This branch has not been deployed

No deployments
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.

Generated source action is skipped after clearing a workspace member target: empty placeholder is compiled

1 participant