From 420fb0941ccd88a33547fa9d5e3e89ec5bb91b4e Mon Sep 17 00:00:00 2001 From: Googler Date: Mon, 24 Aug 2026 14:24:27 -0700 Subject: [PATCH] [9.3.0] Allow the include scanner to resolve generated (output-directory) toolchain headers. RELNOTES: The C++ include scanner now properly resolves headers that are generated at build time and included as part of the toolchain. PiperOrigin-RevId: 970080035 Change-Id: I267fcd63fae455c793a81c4cfde6c9f9c8c9449b (cherry picked from commit 3a9b19c85b11c8a7eaa07013e052bb92d4dc8132) --- .../build/lib/rules/cpp/CppCompileAction.java | 10 ++++++++ .../rules/cpp/CppCompileActionBuilder.java | 14 +++++++++++ .../build/lib/rules/cpp/IncludeScanner.java | 23 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java index 9603c42b08ea6a..6f1a25054eaf5e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java @@ -692,6 +692,11 @@ public NestedSet discoverInputs(ActionExecutionContext actionExecution .setSystemIncludeDirs(systemIncludeDirs) .setCmdlineIncludes(getCmdlineIncludes(options)) .setIsValidUndeclaredHeader(getValidUndeclaredHeaderPredicate()) + // Register generated prunable/toolchain headers as declared so the include scanner + // can resolve them; it never stats output-directory paths. Keep in sync with the + // matching call in the rediscovery path below. See + // IncludeScanningHeaderData.Builder#addDeclaredHeaders. + .addDeclaredHeaders(additionalPrunableHeaders) .build(); additionalInputs = findUsedHeaders(actionExecutionContext, includeScanningHeaderData); if (additionalInputs == null) { @@ -1910,6 +1915,11 @@ public NestedSet getInputFilesForExtraAction( includeScanningHeaderData .setSystemIncludeDirs(getSystemIncludeDirs()) .setCmdlineIncludes(getCmdlineIncludes(getCompilerOptions())) + // Register generated prunable/toolchain headers as declared so the include + // scanner can resolve them; it never stats output-directory paths. Keep in sync + // with the matching call in discoverInputs above. See + // IncludeScanningHeaderData.Builder#addDeclaredHeaders. + .addDeclaredHeaders(additionalPrunableHeaders) .build()); if (usedHeaders == null) { return null; diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java index 34d480b211088c..f8057e3569a310 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java @@ -294,6 +294,20 @@ public CppCompileAction buildAndVerify() throws UnconfiguredActionConfigExceptio .addTransitive(cacheKeyInputs) .build(); NestedSet prunableHeaders = additionalPrunableHeaders; + if (getShouldScanIncludes()) { + // With include scanning enabled, only compiler_files_without_includes is staged as a + // mandatory input; the rest of the toolchain files (compiler_files) are expected to be + // discovered on demand by the include scanner. Generated toolchain headers -- e.g. a + // sysroot whose headers are symlinked into the output tree -- are only discoverable if they + // are known inputs, so fold compiler_files into the prunable set here. They must also be + // registered as declared headers (the scanner never stats output-directory paths); see the + // addDeclaredHeaders calls in discoverInputs below. + prunableHeaders = + NestedSetBuilder.stableOrder() + .addTransitive(additionalPrunableHeaders) + .addTransitive(ccToolchain.getCompilerFiles()) + .build(); + } configuration.modifyExecutionInfo( executionInfo, diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java index 1dd80207401b42..f6073a048ddec7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanner.java @@ -20,6 +20,7 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ExecException; import com.google.devtools.build.lib.analysis.platform.PlatformInfo; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -243,6 +244,28 @@ public Builder setIsValidUndeclaredHeader( return this; } + @CanIgnoreReturnValue + public Builder addDeclaredHeaders(NestedSet headers) { + // pathToDeclaredHeader is a fresh, per-action mutable CompactHashMap created by + // CcCompilationContext#createIncludeScanningHeaderData (which intentionally avoids the + // more expensive ImmutableMap). Mutating it in place here is therefore safe -- it is not + // shared across actions -- and consistent with that method's performance choice. + for (Artifact header : headers.toList()) { + // Only generated (output-directory) headers need to be registered here. Source + // headers already resolve via source-artifact lookup in the include scanner, so + // registering them would be redundant. Skipping them keeps this map empty for the + // common case of a source-file sysroot (e.g. GRTE), leaving those toolchains + // entirely unaffected. Tree artifacts are handled separately and are skipped. + if (!header.isSourceArtifact() && !header.isTreeArtifact()) { + // Use putIfAbsent so a header the target already declared for this exec path takes + // precedence: the target's own mapping is authoritative and must not be shadowed by + // a toolchain/prunable header that happens to share the path. + pathToDeclaredHeader.putIfAbsent(header.getExecPath(), header); + } + } + return this; + } + public IncludeScanningHeaderData build() { return new IncludeScanningHeaderData( pathToDeclaredHeader,