Add a binary to CppCompileAction that is responsible for grepping header files for include statments. This binary is currently only used for an internal feature - but that feature may be supported externally eventually.

RELNOTES: None
PiperOrigin-RevId: 188173513
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
index 977c13c..aeb956c 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
@@ -31,6 +31,7 @@
 import com.google.devtools.build.lib.rules.cpp.CppBuildInfo;
 import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader;
 import com.google.devtools.build.lib.rules.cpp.CppOptions;
+import com.google.devtools.build.lib.rules.cpp.CppRuleClasses.CcIncludeScanningRule;
 import com.google.devtools.build.lib.rules.cpp.CpuTransformer;
 import com.google.devtools.build.lib.rules.platform.PlatformRules;
 
@@ -67,6 +68,7 @@
     builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryBaseRule());
     builder.addRuleDefinition(new BazelCcLibraryRule());
     builder.addRuleDefinition(new BazelCcImportRule());
+    builder.addRuleDefinition(new CcIncludeScanningRule());
 
     builder.addWorkspaceFileSuffix(
         "register_toolchains('@bazel_tools//tools/cpp:dummy_cc_toolchain')\n");
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
index 709336b..9dc21c2f 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
@@ -58,6 +58,7 @@
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
+import com.google.devtools.build.lib.rules.cpp.CppRuleClasses.CcIncludeScanningRule;
 import com.google.devtools.build.lib.rules.cpp.TransitiveLipoInfoProvider;
 import com.google.devtools.build.lib.rules.cpp.transitions.LipoContextCollectorTransition;
 import com.google.devtools.build.lib.util.FileTypeSet;
@@ -143,6 +144,7 @@
     public Metadata getMetadata() {
       return RuleDefinition.Metadata.builder()
           .name("$cc_linking_rule")
+          .ancestors(CcIncludeScanningRule.class)
           .type(RuleClassType.ABSTRACT)
           .build();
     }
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 955e48b..1e7b65b 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
@@ -175,6 +175,7 @@
    */
   private final NestedSet<Artifact> prunableInputs;
 
+  @Nullable private final Artifact grepIncludes;
   private final boolean shouldScanIncludes;
   private final boolean shouldPruneModules;
   private final boolean usePic;
@@ -293,7 +294,8 @@
       ImmutableMap<String, String> environment,
       String actionName,
       CppSemantics cppSemantics,
-      CcToolchainProvider cppProvider) {
+      CcToolchainProvider cppProvider,
+      @Nullable Artifact grepIncludes) {
     this(
         owner,
         allInputs,
@@ -343,7 +345,8 @@
         /*overwrittenVariables=*/ null,
         cppSemantics.needsDotdInputPruning(),
         cppSemantics.needsIncludeValidation(),
-        cppSemantics.getIncludeProcessing());
+        cppSemantics.getIncludeProcessing(),
+        grepIncludes);
     Preconditions.checkArgument(!shouldPruneModules || shouldScanIncludes);
   }
 
@@ -383,7 +386,8 @@
       CcToolchainFeatures.Variables overwrittenVariables,
       boolean needsDotdInputPruning,
       boolean needsIncludeValidation,
-      IncludeProcessing includeProcessing) {
+      IncludeProcessing includeProcessing,
+      @Nullable Artifact grepIncludes) {
     super(owner, inputs, outputs);
     this.localShellEnvironment = localShellEnvironment;
     this.outputFile = outputFile;
@@ -416,6 +420,7 @@
     this.usedModules = usedModules;
     this.topLevelModules = topLevelModules;
     this.overwrittenVariables = overwrittenVariables;
+    this.grepIncludes = grepIncludes;
   }
 
   /**
@@ -644,6 +649,12 @@
     return Collections.unmodifiableMap(legalOuts);
   }
 
+  @Override
+  @Nullable
+  public Artifact getGrepIncludes() {
+    return grepIncludes;
+  }
+
   /**
    * Returns the path where gcc should put the discovered dependency
    * information.
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 6264c8e..013f3e6 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
@@ -78,6 +78,7 @@
   private Map<String, String> environment = new LinkedHashMap<>();
   private CppSemantics cppSemantics;
   private CcToolchainProvider ccToolchain;
+  @Nullable private final Artifact grepIncludes;
   private final ImmutableMap<String, String> localShellEnvironment;
   private final boolean codeCoverageEnabled;
   @Nullable private String actionName;
@@ -90,11 +91,7 @@
    * rule.
    */
   public CppCompileActionBuilder(RuleContext ruleContext, CcToolchainProvider ccToolchain) {
-    this(
-        ruleContext.getActionOwner(),
-        ruleContext.getConfiguration(),
-        getLipoScannableMap(ruleContext, ccToolchain),
-        ccToolchain);
+    this(ruleContext, ccToolchain, ruleContext.getConfiguration());
   }
 
   /** Creates a builder from a rule and configuration. */
@@ -106,7 +103,10 @@
         ruleContext.getActionOwner(),
         configuration,
         getLipoScannableMap(ruleContext, ccToolchain),
-        ccToolchain);
+        ccToolchain,
+        ruleContext.attributes().has("$grep_includes")
+            ? ruleContext.getPrerequisiteArtifact("$grep_includes", Mode.HOST)
+            : null);
   }
 
   /** Creates a builder from a rule and configuration. */
@@ -114,7 +114,8 @@
       ActionOwner actionOwner,
       BuildConfiguration configuration,
       Map<Artifact, IncludeScannable> lipoScannableMap,
-      CcToolchainProvider ccToolchain) {
+      CcToolchainProvider ccToolchain,
+      @Nullable Artifact grepIncludes) {
     this.owner = actionOwner;
     this.configuration = configuration;
     this.cppConfiguration = configuration.getFragment(CppConfiguration.class);
@@ -125,6 +126,7 @@
     this.localShellEnvironment = configuration.getLocalShellEnvironment();
     this.codeCoverageEnabled = configuration.isCodeCoverageEnabled();
     this.ccToolchain = ccToolchain;
+    this.grepIncludes = grepIncludes;
   }
 
   /**
@@ -164,6 +166,7 @@
     this.cppSemantics = other.cppSemantics;
     this.ccToolchain = other.ccToolchain;
     this.actionName = other.actionName;
+    this.grepIncludes = other.grepIncludes;
   }
 
   private static ImmutableMap<Artifact, IncludeScannable> getLipoScannableMap(
@@ -384,7 +387,8 @@
               getLipoScannables(realMandatoryInputs),
               cppSemantics,
               ccToolchain,
-              ImmutableMap.copyOf(executionInfo));
+              ImmutableMap.copyOf(executionInfo),
+              grepIncludes);
     } else {
       action =
           new CppCompileAction(
@@ -419,7 +423,8 @@
               ImmutableMap.copyOf(environment),
               getActionName(),
               cppSemantics,
-              ccToolchain);
+              ccToolchain,
+              grepIncludes);
     }
 
     if (cppSemantics.needsIncludeValidation()) {
@@ -450,6 +455,9 @@
     }
     realMandatoryInputsBuilder.addTransitive(ccCompilationInfo.getAdditionalInputs());
     realMandatoryInputsBuilder.add(Preconditions.checkNotNull(sourceFile));
+    if (grepIncludes != null) {
+      realMandatoryInputsBuilder.add(grepIncludes);
+    }
     return realMandatoryInputsBuilder.build();
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index 0ca8887..f3e22be 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -630,8 +630,10 @@
         && !prerequisite.isSourceArtifact()
         && CPP_FILETYPES.matches(prerequisite.getFilename())) {
       Artifact scanned = getIncludesOutput(ruleContext, prerequisite);
+      Artifact grepIncludes = ruleContext.getPrerequisiteArtifact("$grep_includes", Mode.HOST);
       ruleContext.registerAction(
-          new ExtractInclusionAction(ruleContext.getActionOwner(), prerequisite, scanned));
+          new ExtractInclusionAction(
+              ruleContext.getActionOwner(), prerequisite, scanned, grepIncludes));
       return scanned;
     }
     return null;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppIncludeExtractionContext.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppIncludeExtractionContext.java
index 8b4b638..400fdb9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppIncludeExtractionContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppIncludeExtractionContext.java
@@ -37,7 +37,8 @@
       ActionExecutionContext actionExecutionContext,
       Action resourceOwner,
       Artifact primaryInput,
-      Artifact primaryOutput)
+      Artifact primaryOutput,
+      Artifact grepIncludes)
       throws IOException, ExecException, InterruptedException;
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
index 6245420..0aacc00 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
@@ -14,6 +14,8 @@
 
 package com.google.devtools.build.lib.rules.cpp;
 
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates;
 import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.ALWAYS_LINK_LIBRARY;
 import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.ALWAYS_LINK_PIC_LIBRARY;
@@ -31,11 +33,16 @@
 import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.VERSIONED_SHARED_LIBRARY;
 
 import com.google.devtools.build.lib.analysis.LanguageDependentFragment.LibraryLanguage;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
 import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.analysis.config.HostTransition;
 import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector.InstrumentationSpec;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.Attribute.LabelLateBoundDefault;
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
 import com.google.devtools.build.lib.packages.RuleTransitionFactory;
 import com.google.devtools.build.lib.rules.cpp.transitions.EnableLipoTransition;
 import com.google.devtools.build.lib.util.FileTypeSet;
@@ -178,7 +185,7 @@
 
   /** A string constant for the header_modules_compile feature. */
   public static final String HEADER_MODULE_COMPILE = "header_module_compile";
-  
+
   /** A string constant for the header_module_codegen feature. */
   public static final String HEADER_MODULE_CODEGEN = "header_module_codegen";
 
@@ -364,4 +371,25 @@
 
   /** A string constant for the match-clif action. */
   public static final String MATCH_CLIF = "match_clif";
+
+  /** Ancestor for all rules that do include scanning. */
+  public static final class CcIncludeScanningRule implements RuleDefinition {
+    @Override
+    public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+      return builder
+          .add(
+              attr("$grep_includes", LABEL)
+                  .cfg(HostTransition.INSTANCE)
+                  .value(env.getToolsLabel("//tools/cpp:grep-includes")))
+          .build();
+    }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("$cc_include_scanning_rule")
+          .type(RuleClassType.ABSTRACT)
+          .build();
+    }
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtractInclusionAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtractInclusionAction.java
index 211ae9c..f03d4ee 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtractInclusionAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/ExtractInclusionAction.java
@@ -45,10 +45,13 @@
 
   private static final String GUID = "45b43e5a-4734-43bb-a05e-012313808142";
 
+  private final Artifact grepIncludes;
+
   /** Constructs a new action. */
   public ExtractInclusionAction(
-      ActionOwner owner, Artifact primaryInput, Artifact primaryOutput) {
-    super(owner, ImmutableList.of(primaryInput), ImmutableList.of(primaryOutput));
+      ActionOwner owner, Artifact primaryInput, Artifact primaryOutput, Artifact grepIncludes) {
+    super(owner, ImmutableList.of(primaryInput, grepIncludes), ImmutableList.of(primaryOutput));
+    this.grepIncludes = grepIncludes;
   }
 
   @Override
@@ -72,8 +75,8 @@
     CppIncludeExtractionContext context =
         actionExecutionContext.getContext(CppIncludeExtractionContext.class);
     try {
-      context.extractIncludes(actionExecutionContext, this, getPrimaryInput(),
-          getPrimaryOutput());
+      context.extractIncludes(
+          actionExecutionContext, this, getPrimaryInput(), getPrimaryOutput(), grepIncludes);
     } catch (IOException e) {
       throw new ActionExecutionException(e, this, false);
     } catch (ExecException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
index 93e6bfa..25b2267 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
@@ -80,7 +80,8 @@
       Iterable<IncludeScannable> lipoScannables,
       CppSemantics cppSemantics,
       CcToolchainProvider cppProvider,
-      ImmutableMap<String, String> executionInfo) {
+      ImmutableMap<String, String> executionInfo,
+      Artifact grepIncludes) {
     super(
         owner,
         allInputs,
@@ -120,7 +121,8 @@
         ImmutableMap.<String, String>of(),
         CppCompileAction.CPP_COMPILE,
         cppSemantics,
-        cppProvider);
+        cppProvider,
+        grepIncludes);
     this.tempOutputFile = Preconditions.checkNotNull(tempOutputFile);
   }
 
@@ -172,7 +174,7 @@
               .build()
               .discoverInputsFromDependencies(execRoot, scanningContext.getArtifactResolver());
     }
-     
+
     reply = null; // Clear in-memory .d files early.
 
     // Even cc_fake_binary rules need to properly declare their dependencies...
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScannable.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScannable.java
index 4c97495..f5bf7e9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScannable.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScannable.java
@@ -74,14 +74,14 @@
   List<Artifact> getBuiltInIncludeFiles();
 
   /**
-   * Returns the artifact relative to which the {@code getCmdlineIncludes()} should be interpreted. 
+   * Returns the artifact relative to which the {@code getCmdlineIncludes()} should be interpreted.
    */
   Artifact getMainIncludeScannerSource();
-  
+
   /**
    * Returns an immutable list of sources that the IncludeScanner should scan
    * for this action.
-   * 
+   *
    * <p>Must contain {@code getMainIncludeScannerSource()}.
    */
   Collection<Artifact> getIncludeScannerSources();
@@ -106,4 +106,9 @@
    * should just map to null.
    */
   Map<Artifact, Artifact> getLegalGeneratedScannerFileMap();
+
+  /**
+   * Returns an artifact that is the executable for {@link ExtractInclusionAction}.
+   */
+  Artifact getGrepIncludes();
 }
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 ffde90d..1335470 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
@@ -60,14 +60,14 @@
    *     transitively for compiled header modules as include scanning entry points, and we need to
    *     add the entry points to the inputs here.</li></ol>
    * </p>
-   * 
+   *
    * <p>{@code mainSource} is the source file relative to which the {@code cmdlineIncludes} are
    * interpreted.</p>
    */
   void process(Artifact mainSource, Collection<Artifact> sources,
       Map<Artifact, Artifact> legalOutputPaths, List<PathFragment> includeDirs,
       List<PathFragment> quoteIncludeDirs, List<String> cmdlineIncludes,
-      Set<Artifact> includes, ActionExecutionContext actionExecutionContext)
+      Set<Artifact> includes, ActionExecutionContext actionExecutionContext, Artifact grepIncludes)
       throws IOException, ExecException, InterruptedException;
 
   /** Supplies IncludeScanners upon request. */
@@ -142,7 +142,8 @@
           Artifact mainSource =  scannable.getMainIncludeScannerSource();
           Collection<Artifact> sources = scannable.getIncludeScannerSources();
           scanner.process(mainSource, sources, legalOutputPaths, quoteIncludeDirs,
-              includeDirList, cmdlineIncludes, includes, actionExecutionContext);
+              includeDirList, cmdlineIncludes, includes, actionExecutionContext,
+              action.getGrepIncludes());
         }
       } catch (IOException e) {
         throw new EnvironmentalExecException(e.getMessage());
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/DummyIncludeScanningContextProvider.java b/src/main/java/com/google/devtools/build/lib/standalone/DummyIncludeScanningContextProvider.java
index 2c92f75..33a076a 100644
--- a/src/main/java/com/google/devtools/build/lib/standalone/DummyIncludeScanningContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/standalone/DummyIncludeScanningContextProvider.java
@@ -48,7 +48,8 @@
         ActionExecutionContext actionExecutionContext,
         Action resourceOwner,
         Artifact primaryInput,
-        Artifact primaryOutput)
+        Artifact primaryOutput,
+        Artifact grepIncludes)
         throws IOException {
       FileSystemUtils.writeContent(primaryOutput.getPath(), new byte[]{});
     }
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
index 997939c..267005b 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
@@ -120,7 +120,8 @@
               && !pathString.startsWith("tools/cpp/build_interface_so")
               && !(pathString.contains("/internal/_middlemen") && basename.contains("crosstool"))
               && !pathString.startsWith("_bin/build_interface_so")
-              && !pathString.endsWith(".cppmap");
+              && !pathString.endsWith(".cppmap")
+              && !pathString.startsWith("tools/cpp/grep-includes");
         }
       };
 
@@ -707,13 +708,16 @@
         "filegroup(",
         "    name = 'link_dynamic_library',",
         "    srcs = ['link_dynamic_library.sh'],",
-        ")");
+        ")",
+        "exports_files(['grep-includes'])");
     if (config.isRealFileSystem()) {
       config.linkTool("tools/cpp/link_dynamic_library.sh");
       config.linkTool("tools/cpp/build_interface_so");
+      config.linkTool("tools/cpp/grep-includes");
     } else {
       config.create("tools/cpp/link_dynamic_library.sh", "");
       config.create("tools/cpp/build_interface_so", "");
+      config.create("tools/cpp/grep-includes", "");
     }
   }
 
diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD
index ac24dcf..3ba1050 100644
--- a/tools/cpp/BUILD
+++ b/tools/cpp/BUILD
@@ -14,6 +14,11 @@
 )
 
 filegroup(
+    name = "grep-includes",
+    srcs = ["grep-includes.sh"],
+)
+
+filegroup(
     name = "empty",
     srcs = [],
 )
diff --git a/tools/cpp/grep-includes.sh b/tools/cpp/grep-includes.sh
new file mode 100755
index 0000000..ee51361
--- /dev/null
+++ b/tools/cpp/grep-includes.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Copyright 2018 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# TODO(bazel-team): Support include scanning and grep-includes in Bazel
+echo "grep-includes is not supported by Bazel"
+exit 1