Make thinlto action command lines standalone

This cl introduces an incompatible flag `--incompatible_make_thinlto_command_lines_standalone`, which when flipped will change Bazel's handling of thinlto:

1) lto-backend action_config now has to be defined in the CcToolchainConfigInfo
2) lto-indexing action is split into:
    * lto-index-for-executable
    * lto-index-for-dynamic-library
    * lto-index-for-nodeps-dynamic-library
3) all these need an action_config too
4) lto-indexing action is completely ignored
5) lto indexing command line is now defined independently of c++-link-executable, c++-link-dynamic-library, and c++-link-nodeps-dynamic-library, flags are no longer reused.

https://github.com/bazelbuild/bazel/issues/6791

RELNOTES: Incompatible flag `--incompatible_make_thinlto_command_lines_standalone` has been added. See https://github.com/bazelbuild/bazel/issues/6791 for details.
PiperOrigin-RevId: 243988905
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
index f184592..bedea9a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
@@ -122,10 +122,14 @@
           CppActionNames.PREPROCESS_ASSEMBLE,
           CppActionNames.CLIF_MATCH,
           CppActionNames.LINKSTAMP_COMPILE,
-          CppActionNames.CC_FLAGS_MAKE_VARIABLE);
+          CppActionNames.CC_FLAGS_MAKE_VARIABLE,
+          CppActionNames.LTO_BACKEND);
 
   public static final ImmutableSet<String> ALL_LINK_ACTIONS =
       ImmutableSet.of(
+          CppActionNames.LTO_INDEX_EXECUTABLE,
+          CppActionNames.LTO_INDEX_DYNAMIC_LIBRARY,
+          CppActionNames.LTO_INDEX_NODEPS_DYNAMIC_LIBRARY,
           LinkTargetType.EXECUTABLE.getActionName(),
           Link.LinkTargetType.DYNAMIC_LIBRARY.getActionName(),
           Link.LinkTargetType.NODEPS_DYNAMIC_LIBRARY.getActionName());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java
index 2e0c3d6..e6a11cb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java
@@ -979,6 +979,20 @@
           getActionConfig(
               Joiner.on("\n")
                   .join(
+                      "  config_name: 'lto-backend'",
+                      "  action_name: 'lto-backend'",
+                      "  tool {",
+                      "    tool_path: '" + gccToolPath + "'",
+                      "  }",
+                      "  implies: 'legacy_compile_flags'",
+                      "  implies: 'user_compile_flags'",
+                      "  implies: 'sysroot'",
+                      "  implies: 'unfiltered_compile_flags'",
+                      "  implies: 'compiler_input_flags'",
+                      "  implies: 'compiler_output_flags'")),
+          getActionConfig(
+              Joiner.on("\n")
+                  .join(
                       "  config_name: 'c-compile'",
                       "  action_name: 'c-compile'",
                       "  tool {",
@@ -1070,6 +1084,27 @@
           getActionConfig(
               Joiner.on("\n")
                   .join(
+                      "  config_name: 'lto-index-for-executable'",
+                      "  action_name: 'lto-index-for-executable'",
+                      "  tool {",
+                      "    tool_path: '" + gccToolPath + "'",
+                      "  }",
+                      "  implies: 'symbol_counts'",
+                      "  implies: 'strip_debug_symbols'",
+                      "  implies: 'linkstamps'",
+                      "  implies: 'output_execpath_flags'",
+                      "  implies: 'runtime_library_search_directories'",
+                      "  implies: 'library_search_directories'",
+                      "  implies: 'libraries_to_link'",
+                      "  implies: 'force_pic_flags'",
+                      "  implies: 'user_link_flags'",
+                      "  implies: 'legacy_link_flags'",
+                      "  implies: 'linker_param_file'",
+                      "  implies: 'fission_support'",
+                      "  implies: 'sysroot'")),
+          getActionConfig(
+              Joiner.on("\n")
+                  .join(
                       "  config_name: 'c++-link-nodeps-dynamic-library'",
                       "  action_name: 'c++-link-nodeps-dynamic-library'",
                       "  tool {",
@@ -1093,6 +1128,29 @@
           getActionConfig(
               Joiner.on("\n")
                   .join(
+                      "  config_name: 'lto-index-for-nodeps-dynamic-library'",
+                      "  action_name: 'lto-index-for-nodeps-dynamic-library'",
+                      "  tool {",
+                      "    tool_path: '" + gccToolPath + "'",
+                      "  }",
+                      "  implies: 'build_interface_libraries'",
+                      "  implies: 'dynamic_library_linker_tool'",
+                      "  implies: 'symbol_counts'",
+                      "  implies: 'strip_debug_symbols'",
+                      "  implies: 'shared_flag'",
+                      "  implies: 'linkstamps'",
+                      "  implies: 'output_execpath_flags'",
+                      "  implies: 'runtime_library_search_directories'",
+                      "  implies: 'library_search_directories'",
+                      "  implies: 'libraries_to_link'",
+                      "  implies: 'user_link_flags'",
+                      "  implies: 'legacy_link_flags'",
+                      "  implies: 'linker_param_file'",
+                      "  implies: 'fission_support'",
+                      "  implies: 'sysroot'")),
+          getActionConfig(
+              Joiner.on("\n")
+                  .join(
                       "  config_name: 'c++-link-dynamic-library'",
                       "  action_name: 'c++-link-dynamic-library'",
                       "  tool {",
@@ -1116,6 +1174,29 @@
           getActionConfig(
               Joiner.on("\n")
                   .join(
+                      "  config_name: 'lto-index-for-dynamic-library'",
+                      "  action_name: 'lto-index-for-dynamic-library'",
+                      "  tool {",
+                      "    tool_path: '" + gccToolPath + "'",
+                      "  }",
+                      "  implies: 'build_interface_libraries'",
+                      "  implies: 'dynamic_library_linker_tool'",
+                      "  implies: 'symbol_counts'",
+                      "  implies: 'strip_debug_symbols'",
+                      "  implies: 'shared_flag'",
+                      "  implies: 'linkstamps'",
+                      "  implies: 'output_execpath_flags'",
+                      "  implies: 'runtime_library_search_directories'",
+                      "  implies: 'library_search_directories'",
+                      "  implies: 'libraries_to_link'",
+                      "  implies: 'user_link_flags'",
+                      "  implies: 'legacy_link_flags'",
+                      "  implies: 'linker_param_file'",
+                      "  implies: 'fission_support'",
+                      "  implies: 'sysroot'")),
+          getActionConfig(
+              Joiner.on("\n")
+                  .join(
                       "  config_name: 'c++-link-static-library'",
                       "  action_name: 'c++-link-static-library'",
                       "  tool {",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionNames.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionNames.java
index 6547219..948f204 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionNames.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionNames.java
@@ -69,5 +69,13 @@
   public static final String OBJCPP_EXECUTABLE = "objc++-executable";
 
   public static final String LTO_INDEXING = "lto-indexing";
+  /** Name of the action producing thinlto index for dynamic library. */
+  public static final String LTO_INDEX_DYNAMIC_LIBRARY = "lto-index-for-dynamic-library";
+  /** Name of the action producing thinlto index for nodeps dynamic library. */
+  public static final String LTO_INDEX_NODEPS_DYNAMIC_LIBRARY =
+      "lto-index-for-nodeps-dynamic-library";
+  /** Name of the action producing thinlto index for executable binary. */
+  public static final String LTO_INDEX_EXECUTABLE = "lto-index-for-executable";
+
   public static final String LTO_BACKEND = "lto-backend";
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
index 8a91339..8522e37 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
@@ -665,4 +665,8 @@
   public boolean saveFeatureState() {
     return cppOptions.saveFeatureState;
   }
+
+  public boolean useStandaloneLtoIndexingCommandLines() {
+    return cppOptions.useStandaloneLtoIndexingCommandLines;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
index 86b7e7d..ac21918 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
@@ -191,6 +191,20 @@
 
   /** Returns the action name for purposes of querying the crosstool. */
   private String getActionName() {
+    // We check that this action is not lto-indexing, or when it is, it's either for executable
+    // or transitive or nodeps dynamic library.
+    Preconditions.checkArgument(
+        !isLtoIndexing || linkType.isExecutable() || linkType.isDynamicLibrary());
+    if (isLtoIndexing && cppConfiguration.useStandaloneLtoIndexingCommandLines()) {
+      if (linkType.isExecutable()) {
+        return CppActionNames.LTO_INDEX_EXECUTABLE;
+      } else if (linkType.isTransitiveDynamicLibrary()) {
+        return CppActionNames.LTO_INDEX_DYNAMIC_LIBRARY;
+      } else {
+        return CppActionNames.LTO_INDEX_NODEPS_DYNAMIC_LIBRARY;
+      }
+    }
+
     return linkType.getActionName();
   }
 
@@ -859,6 +873,13 @@
 
     CcToolchainVariables variables;
     try {
+      ImmutableList.Builder<String> userLinkFlags =
+          ImmutableList.<String>builder().addAll(linkopts).addAll(cppConfiguration.getLinkopts());
+
+      if (isLtoIndexing && cppConfiguration.useStandaloneLtoIndexingCommandLines()) {
+        userLinkFlags.addAll(cppConfiguration.getLtoIndexOptions());
+      }
+
       variables =
           LinkBuildVariables.setupVariables(
               getLinkType().linkerOrArchiver().equals(LinkerOrArchiver.LINKER),
@@ -875,10 +896,7 @@
               featureConfiguration,
               useTestOnlyFlags,
               isLtoIndexing,
-              ImmutableList.<String>builder()
-                  .addAll(linkopts)
-                  .addAll(cppConfiguration.getLinkopts())
-                  .build(),
+              userLinkFlags.build(),
               toolchain.getInterfaceSoBuilder().getExecPathString(),
               interfaceOutput != null ? interfaceOutput.getExecPathString() : null,
               ltoOutputRootPrefix,
@@ -921,6 +939,7 @@
 
     LinkCommandLine.Builder linkCommandLineBuilder =
         new LinkCommandLine.Builder()
+            .setActionName(getActionName())
             .setLinkerInputArtifacts(expandedLinkerArtifacts)
             .setLinkTargetType(linkType)
             .setLinkingMode(linkingMode)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
index 7600c15..5de5169 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
@@ -739,6 +739,20 @@
   public boolean dontEnableHostNonhost;
 
   @Option(
+      name = "incompatible_make_thinlto_command_lines_standalone",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.TOOLCHAIN,
+      effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS},
+      metadataTags = {
+        OptionMetadataTag.INCOMPATIBLE_CHANGE,
+        OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
+      },
+      help =
+          "If true, Bazel will not reuse C++ link action command lines for lto indexing command "
+              + "lines (see https://github.com/bazelbuild/bazel/issues/6791 for more information).")
+  public boolean useStandaloneLtoIndexingCommandLines;
+
+  @Option(
       name = "incompatible_require_ctx_in_configure_features",
       defaultValue = "false",
       documentationCategory = OptionDocumentationCategory.TOOLCHAIN,
@@ -920,6 +934,7 @@
     host.removeLegacyWholeArchive = removeLegacyWholeArchive;
     host.dontEnableHostNonhost = dontEnableHostNonhost;
     host.requireCtxInConfigureFeatures = requireCtxInConfigureFeatures;
+    host.useStandaloneLtoIndexingCommandLines = useStandaloneLtoIndexingCommandLines;
     return host;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
index a029a9d..91647c8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
@@ -245,13 +245,18 @@
     public String getActionName() {
       return actionName;
     }
-    
-    /** Returns true iff this link type is executable */
+
+    /** Returns true iff this link type is executable. */
     public boolean isExecutable() {
       return (executable == Executable.EXECUTABLE);
     }
 
-    /** Returns true iff this link type is a dynamic library or transitive dynamic library */
+    /** Returns true iff this link type is a transitive dynamic library. */
+    public boolean isTransitiveDynamicLibrary() {
+      return this == DYNAMIC_LIBRARY;
+    }
+
+    /** Returns true iff this link type is a dynamic library or transitive dynamic library. */
     public boolean isDynamicLibrary() {
       return this == NODEPS_DYNAMIC_LIBRARY || this == DYNAMIC_LIBRARY;
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java
index a79102e..364a757 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java
@@ -236,7 +236,7 @@
     }
 
     Iterable<String> userLinkFlagsWithLtoIndexingIfNeeded;
-    if (!isLtoIndexing) {
+    if (!isLtoIndexing || cppConfiguration.useStandaloneLtoIndexingCommandLines()) {
       userLinkFlagsWithLtoIndexingIfNeeded = userLinkFlags;
     } else {
       ImmutableList.Builder<String> opts = ImmutableList.builder();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java
index f2a5b32..d03d99b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java
@@ -434,9 +434,9 @@
     private CcToolchainVariables variables;
     private FeatureConfiguration featureConfiguration;
     private boolean doNotSplitLinkingCmdLine;
+    private String actionName;
 
     public LinkCommandLine build() {
-
       if (linkTargetType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER) {
         Preconditions.checkArgument(
             buildInfoHeaderArtifacts.isEmpty(),
@@ -447,8 +447,6 @@
         variables = CcToolchainVariables.EMPTY;
       }
 
-      String actionName = linkTargetType.getActionName();
-
       return new LinkCommandLine(
           actionName,
           forcedToolPath,
@@ -557,5 +555,10 @@
       this.doNotSplitLinkingCmdLine = true;
       return this;
     }
+
+    public Builder setActionName(String actionName) {
+      this.actionName = actionName;
+      return this;
+    }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendArtifacts.java
index c8b2121..04d2d84 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendArtifacts.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendArtifacts.java
@@ -233,11 +233,6 @@
     builder.setProgressMessage("LTO Backend Compile %s", objectFile.getExecPath());
     builder.setMnemonic("CcLtoBackendCompile");
 
-    // The command-line doesn't specify the full path to clang++, so we set it in the
-    // environment.
-    PathFragment compiler = ccToolchain.getToolPathFragment(Tool.GCC, ruleErrorConsumer);
-
-    builder.setExecutable(compiler);
     CcToolchainVariables.Builder buildVariablesBuilder =
         CcToolchainVariables.builder(ccToolchain.getBuildVariables(buildOptions, cppConfiguration));
     if (index != null) {
@@ -277,8 +272,24 @@
     buildVariablesBuilder.addStringSequenceVariable(
         CompileBuildVariables.USER_COMPILE_FLAGS.getVariableName(), userCompileFlags);
 
-    List<String> execArgs = new ArrayList<>();
     CcToolchainVariables buildVariables = buildVariablesBuilder.build();
+
+    if (cppConfiguration.useStandaloneLtoIndexingCommandLines()) {
+      if (!featureConfiguration.actionIsConfigured(CppActionNames.LTO_BACKEND)) {
+        throw ruleErrorConsumer.throwWithRuleError(
+            "Thinlto build is requested, but the C++ toolchain doesn't define an action_config for"
+                + " 'lto-backend' action.");
+      }
+      PathFragment compiler =
+          PathFragment.create(
+              featureConfiguration.getToolPathForAction(CppActionNames.LTO_BACKEND));
+      builder.setExecutable(compiler);
+    } else {
+      PathFragment compiler = ccToolchain.getToolPathFragment(Tool.GCC, ruleErrorConsumer);
+      builder.setExecutable(compiler);
+    }
+
+    List<String> execArgs = new ArrayList<>();
     execArgs.addAll(
         CppHelper.getCommandLine(
             ruleErrorConsumer, featureConfiguration, buildVariables, CppActionNames.LTO_BACKEND));
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/cc_toolchain_config.bzl b/src/test/java/com/google/devtools/build/lib/analysis/mock/cc_toolchain_config.bzl
index 4052bf9..05be8a1 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/cc_toolchain_config.bzl
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/cc_toolchain_config.bzl
@@ -457,6 +457,20 @@
             ],
         ),
         flag_set(
+            actions = [
+                ACTION_NAMES.lto_index_for_executable,
+                ACTION_NAMES.lto_index_for_dynamic_library,
+                ACTION_NAMES.lto_index_for_nodeps_dynamic_library,
+            ],
+            flag_groups = [
+                flag_group(
+                    flags = ["--i_come_from_standalone_lto_index=%{user_link_flags}"],
+                    iterate_over = "user_link_flags",
+                    expand_if_available = "user_link_flags",
+                ),
+            ],
+        ),
+        flag_set(
             actions = [ACTION_NAMES.lto_indexing],
             flag_groups = [
                 flag_group(
diff --git a/tools/build_defs/cc/action_names.bzl b/tools/build_defs/cc/action_names.bzl
index 8fd2026..60e8a5f 100644
--- a/tools/build_defs/cc/action_names.bzl
+++ b/tools/build_defs/cc/action_names.bzl
@@ -43,6 +43,15 @@
 # Name of the action producing ThinLto index.
 LTO_INDEXING_ACTION_NAME = "lto-indexing"
 
+# Name of the action producing ThinLto index for executable.
+LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME = "lto-index-for-executable"
+
+# Name of the action producing ThinLto index for dynamic library.
+LTO_INDEX_FOR_DYNAMIC_LIBRARY_ACTION_NAME = "lto-index-for-dynamic-library"
+
+# Name of the action producing ThinLto index for nodeps dynamic library.
+LTO_INDEX_FOR_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME = "lto-index-for-nodeps-dynamic-library"
+
 # Name of the action compiling lto bitcodes into native objects.
 LTO_BACKEND_ACTION_NAME = "lto-backend"
 
@@ -95,6 +104,9 @@
     preprocess_assemble = PREPROCESS_ASSEMBLE_ACTION_NAME,
     lto_indexing = LTO_INDEXING_ACTION_NAME,
     lto_backend = LTO_BACKEND_ACTION_NAME,
+    lto_index_for_executable = LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME,
+    lto_index_for_dynamic_library = LTO_INDEX_FOR_DYNAMIC_LIBRARY_ACTION_NAME,
+    lto_index_for_nodeps_dynamic_library = LTO_INDEX_FOR_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME,
     cpp_link_executable = CPP_LINK_EXECUTABLE_ACTION_NAME,
     cpp_link_dynamic_library = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
     cpp_link_nodeps_dynamic_library = CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME,