C++: Removes CppModel class

The logic is split between CcCompilationHelper and CcLinkingHelper.

RELNOTES:none
PiperOrigin-RevId: 185809915
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index 727db97..49a3264 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -259,7 +259,6 @@
                   ruleContext.getConfiguration())
               .fromCommon(common)
               .addDeps(ImmutableList.of(CppHelper.mallocForTarget(ruleContext)))
-              .setFake(fake)
               .enableInterfaceSharedObjects();
       linkingHelper.setStaticLinkType(LinkTargetType.STATIC_LIBRARY);
       ccLinkingOutputs =
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 e9ae312..69c3f60 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
@@ -70,6 +70,21 @@
  */
 public final class CcCommon {
 
+  /** Name of the build variable for the sysroot path variable name. */
+  public static final String SYSROOT_VARIABLE_NAME = "sysroot";
+
+  /** Name of the build variable for the path to the input file being processed. */
+  public static final String INPUT_FILE_VARIABLE_NAME = "input_file";
+
+  /**
+   * Name of the build variable for includes that compiler needs to include into sources to be
+   * compiled.
+   */
+  public static final String INCLUDES_VARIABLE_NAME = "includes";
+
+  /** Name of the build variable for stripopts for the strip action. */
+  public static final String STRIPOPTS_VARIABLE_NAME = "stripopts";
+
   private static final String NO_COPTS_ATTRIBUTE = "nocopts";
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
index a7c1615..f9149ea 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
@@ -20,10 +20,13 @@
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
+import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
 import com.google.devtools.build.lib.analysis.AnalysisUtils;
 import com.google.devtools.build.lib.analysis.LanguageDependentFragment;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
@@ -33,20 +36,27 @@
 import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder;
 import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
+import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode;
 import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.FileType;
 import com.google.devtools.build.lib.util.FileTypeSet;
 import com.google.devtools.build.lib.util.Pair;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -61,7 +71,7 @@
 /**
  * A class to create C/C++ compile actions in a way that is consistent with cc_library. Rules that
  * generate source files and emulate cc_library on top of that should use this class instead of the
- * lower-level APIs in CppHelper and CppModel.
+ * lower-level APIs in CppHelper and CppCompileActionBuilder.
  *
  * <p>Rules that want to use this class are required to have implicit dependencies on the toolchain,
  * the STL, the lipo context, and so on. Optionally, they can also have copts, and malloc
@@ -74,6 +84,97 @@
           + "hidden_header_tokens"
           + OutputGroupInfo.INTERNAL_SUFFIX;
 
+  private static final String PIC_CONFIGURATION_ERROR =
+      "PIC compilation is requested but the toolchain does not support it";
+  /** Name of the build variable for the path to the source file being compiled. */
+  public static final String SOURCE_FILE_VARIABLE_NAME = "source_file";
+
+  /** Name of the build variable for the path to the compilation output file. */
+  public static final String OUTPUT_FILE_VARIABLE_NAME = "output_file";
+
+  /**
+   * Build variable for all flags coming from copt rule attribute, and from --copt, --cxxopt, or
+   * --conlyopt options.
+   */
+  public static final String USER_COMPILE_FLAGS_VARIABLE_NAME = "user_compile_flags";
+
+  /**
+   * Build variable for all flags coming from legacy crosstool fields, such as compiler_flag,
+   * optional_compiler_flag, cxx_flag, optional_cxx_flag.
+   */
+  public static final String LEGACY_COMPILE_FLAGS_VARIABLE_NAME = "legacy_compile_flags";
+
+  /** Build variable for flags coming from unfiltered_cxx_flag CROSSTOOL fields. */
+  public static final String UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME = "unfiltered_compile_flags";
+
+  /**
+   * Name of the build variable for the path to the compilation output file in case of preprocessed
+   * source.
+   */
+  public static final String OUTPUT_PREPROCESS_FILE_VARIABLE_NAME = "output_preprocess_file";
+
+  /** Name of the build variable for the path to the output file when output is an object file. */
+  public static final String OUTPUT_OBJECT_FILE_VARIABLE_NAME = "output_object_file";
+
+  /**
+   * Name of the build variable for the collection of include paths.
+   *
+   * @see CppCompilationContext#getIncludeDirs().
+   */
+  public static final String INCLUDE_PATHS_VARIABLE_NAME = "include_paths";
+
+  /**
+   * Name of the build variable for the collection of quote include paths.
+   *
+   * @see CppCompilationContext#getIncludeDirs().
+   */
+  public static final String QUOTE_INCLUDE_PATHS_VARIABLE_NAME = "quote_include_paths";
+
+  /**
+   * Name of the build variable for the collection of system include paths.
+   *
+   * @see CppCompilationContext#getIncludeDirs().
+   */
+  public static final String SYSTEM_INCLUDE_PATHS_VARIABLE_NAME = "system_include_paths";
+
+  /** Name of the build variable for the collection of macros defined for preprocessor. */
+  public static final String PREPROCESSOR_DEFINES_VARIABLE_NAME = "preprocessor_defines";
+
+  /** Name of the build variable present when the output is compiled as position independent. */
+  public static final String PIC_VARIABLE_NAME = "pic";
+
+  /**
+   * Name of the build variable for the path to the compilation output file in case of assembly
+   * source.
+   */
+  private static final String OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME = "output_assembly_file";
+
+  /** Name of the build variable for the dependency file path */
+  private static final String DEPENDENCY_FILE_VARIABLE_NAME = "dependency_file";
+
+  /** Name of the build variable for the module file name. */
+  private static final String MODULE_NAME_VARIABLE_NAME = "module_name";
+
+  /** Name of the build variable for the module map file name. */
+  private static final String MODULE_MAP_FILE_VARIABLE_NAME = "module_map_file";
+
+  /** Name of the build variable for the dependent module map file name. */
+  private static final String DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME =
+      "dependent_module_map_files";
+
+  /** Name of the build variable for the collection of module files. */
+  private static final String MODULE_FILES_VARIABLE_NAME = "module_files";
+
+  /** Name of the build variable for the gcov coverage file path. */
+  private static final String GCOV_GCNO_FILE_VARIABLE_NAME = "gcov_gcno_file";
+
+  /** Name of the build variable for the per object debug info file. */
+  private static final String PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME =
+      "per_object_debug_info_file";
+
+  /** Name of the build variable for the LTO indexing bitcode file. */
+  private static final String LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME = "lto_indexing_bitcode_file";
+
   /**
    * A group of source file types and action names for builds controlled by CcCompilationHelper.
    * Determines what file types CcCompilationHelper considers sources and what action configs are
@@ -155,6 +256,7 @@
   private final RuleContext ruleContext;
   private final CppSemantics semantics;
   private final BuildConfiguration configuration;
+  private final CppConfiguration cppConfiguration;
 
   private final List<Artifact> publicHeaders = new ArrayList<>();
   private final List<Artifact> nonModuleMapHeaders = new ArrayList<>();
@@ -190,11 +292,15 @@
   private final FeatureConfiguration featureConfiguration;
   private final CcToolchainProvider ccToolchain;
   private final FdoSupportProvider fdoSupport;
+  private final ImmutableSet<String> features;
   private boolean useDeps = true;
   private boolean generateModuleMap = true;
   private String purpose = null;
   private boolean generateNoPic = true;
 
+  // TODO(plf): Pull out of class.
+  private CppCompilationContext cppCompilationContext;
+
   /**
    * Creates a CcCompilationHelper.
    *
@@ -248,6 +354,9 @@
     this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
     this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
     this.configuration = Preconditions.checkNotNull(configuration);
+    this.cppConfiguration =
+        Preconditions.checkNotNull(ruleContext.getFragment(CppConfiguration.class));
+    this.features = ruleContext.getFeatures();
   }
 
   /**
@@ -645,9 +754,7 @@
       }
     }
 
-    CppModel model = initializeCppModel();
-    CppCompilationContext cppCompilationContext = initializeCppCompilationContext(model);
-    model.setContext(cppCompilationContext);
+    cppCompilationContext = initializeCppCompilationContext();
 
     boolean compileHeaderModules = featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES);
     Preconditions.checkState(
@@ -655,7 +762,7 @@
         "All cc rules must support module maps.");
 
     // Create compile actions (both PIC and non-PIC).
-    CcCompilationOutputs ccOutputs = model.createCcCompileActions();
+    CcCompilationOutputs ccOutputs = createCcCompileActions();
     if (!objectFiles.isEmpty() || !picObjectFiles.isEmpty()) {
       // Merge the pre-compiled object files into the compiler outputs.
       ccOutputs =
@@ -703,22 +810,6 @@
     return new CompilationInfo(providers.build(), outputGroups, ccOutputs, cppCompilationContext);
   }
 
-  /** Creates the C/C++ compilation action creator. */
-  private CppModel initializeCppModel() {
-    return new CppModel(
-            ruleContext, semantics, ccToolchain, fdoSupport, configuration, copts, coptsFilter)
-        .addCompilationUnitSources(compilationUnitSources)
-        .addCompilationMandatoryInputs(compilationMandatoryInputs)
-        .addAdditionalIncludeScanningRoots(additionalIncludeScanningRoots)
-        .setFake(fake)
-        .setGenerateNoPic(generateNoPic)
-        // Note: this doesn't actually save the temps, it just makes the CppModel use the
-        // configurations --save_temps setting to decide whether to actually save the temps.
-        .setSaveTemps(true)
-        .setFeatureConfiguration(featureConfiguration)
-        .addVariablesExtension(variablesExtensions);
-  }
-
   @Immutable
   private static class PublicHeaders {
     private final ImmutableList<Artifact> headers;
@@ -853,17 +944,12 @@
             .getRelative(ruleContext.getUniqueDirectory("_virtual_includes")));
   }
 
-  /** Creates context for cc compile action from generated inputs. */
-  public CppCompilationContext initializeCppCompilationContext() {
-    return initializeCppCompilationContext(initializeCppModel());
-  }
-
   /**
    * Create context for cc compile action from generated inputs.
    *
    * <p>TODO(plf): Try to pull out CppCompilationContext building out of this class.
    */
-  private CppCompilationContext initializeCppCompilationContext(CppModel model) {
+  public CppCompilationContext initializeCppCompilationContext() {
     CppCompilationContext.Builder contextBuilder = new CppCompilationContext.Builder(ruleContext);
 
     // Setup the include path; local include directories come before those inherited from deps or
@@ -959,11 +1045,11 @@
         ruleContext.registerAction(
             createModuleMapAction(cppModuleMap, publicHeaders, dependentModuleMaps, compiled));
       }
-      if (model.getGeneratesPicHeaderModule()) {
-        contextBuilder.setPicHeaderModule(model.getPicHeaderModule(cppModuleMap.getArtifact()));
+      if (getGeneratesPicHeaderModule()) {
+        contextBuilder.setPicHeaderModule(getPicHeaderModule(cppModuleMap.getArtifact()));
       }
-      if (model.getGeneratesNoPicHeaderModule()) {
-        contextBuilder.setHeaderModule(model.getHeaderModule(cppModuleMap.getArtifact()));
+      if (getGeneratesNoPicHeaderModule()) {
+        contextBuilder.setHeaderModule(getHeaderModule(cppModuleMap.getArtifact()));
       }
       if (!compiled
           && featureConfiguration.isEnabled(CppRuleClasses.PARSE_HEADERS)
@@ -986,6 +1072,83 @@
     return contextBuilder.build();
   }
 
+  /**
+   * Collects all preprocessed header files (*.h.processed) from dependencies and the current rule.
+   */
+  public static NestedSet<Artifact> collectHeaderTokens(
+      RuleContext ruleContext, CcCompilationOutputs ccCompilationOutputs) {
+    NestedSetBuilder<Artifact> headerTokens = NestedSetBuilder.stableOrder();
+    for (OutputGroupInfo dep :
+        ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupInfo.SKYLARK_CONSTRUCTOR)) {
+      headerTokens.addTransitive(dep.getOutputGroup(CcCompilationHelper.HIDDEN_HEADER_TOKENS));
+    }
+    if (ruleContext.getFragment(CppConfiguration.class).processHeadersInDependencies()) {
+      headerTokens.addAll(ccCompilationOutputs.getHeaderTokenFiles());
+    }
+    return headerTokens.build();
+  }
+
+  public void registerAdditionalModuleMap(CppModuleMap cppModuleMap) {
+    this.additionalCppModuleMaps.add(Preconditions.checkNotNull(cppModuleMap));
+  }
+
+  /** Don't generate a module map for this target if a custom module map is provided. */
+  public CcCompilationHelper doNotGenerateModuleMap() {
+    generateModuleMap = false;
+    return this;
+  }
+
+  /**
+   * Sets the purpose for the context.
+   *
+   * @see CppCompilationContext.Builder#setPurpose
+   * @param purpose must be a string which is suitable for use as a filename. A single rule may have
+   *     many middlemen with distinct purposes.
+   */
+  public CcCompilationHelper setPurpose(@Nullable String purpose) {
+    this.purpose = purpose;
+    return this;
+  }
+
+  /**
+   * Supplier that computes legacy_compile_flags lazily at the execution phase.
+   *
+   * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only
+   * to arguments (to prevent accidental capture of enclosing instance which could regress memory).
+   */
+  public static Supplier<ImmutableList<String>> getLegacyCompileFlagsSupplier(
+      CppConfiguration cppConfiguration,
+      CcToolchainProvider toolchain,
+      String sourceFilename,
+      ImmutableSet<String> features) {
+    return () -> {
+      ImmutableList.Builder<String> legacyCompileFlags = ImmutableList.builder();
+      legacyCompileFlags.addAll(
+          CppHelper.getCompilerOptions(cppConfiguration, toolchain, features));
+      if (CppFileTypes.C_SOURCE.matches(sourceFilename)) {
+        legacyCompileFlags.addAll(cppConfiguration.getCOptions());
+      }
+      if (CppFileTypes.CPP_SOURCE.matches(sourceFilename)
+          || CppFileTypes.CPP_HEADER.matches(sourceFilename)
+          || CppFileTypes.CPP_MODULE_MAP.matches(sourceFilename)
+          || CppFileTypes.CLIF_INPUT_PROTO.matches(sourceFilename)) {
+        legacyCompileFlags.addAll(CppHelper.getCxxOptions(cppConfiguration, toolchain, features));
+      }
+      return legacyCompileFlags.build();
+    };
+  }
+
+  /**
+   * Supplier that computes unfiltered_compile_flags lazily at the execution phase.
+   *
+   * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only
+   * to arguments (to prevent accidental capture of enclosing instance which could regress memory).
+   */
+  public static Supplier<ImmutableList<String>> getUnfilteredCompileFlagsSupplier(
+      CcToolchainProvider ccToolchain, ImmutableSet<String> features) {
+    return () -> ccToolchain.getUnfilteredCompilerOptions(features);
+  }
+
   private UmbrellaHeaderAction createUmbrellaHeaderAction(
       Artifact umbrellaHeader, PublicHeaders publicHeaders) {
     return new UmbrellaHeaderAction(
@@ -1041,19 +1204,6 @@
     return Iterables.filter(result, Predicates.<CppModuleMap>notNull());
   }
 
-  static NestedSet<Artifact> collectHeaderTokens(
-      RuleContext ruleContext, CcCompilationOutputs ccCompilationOutputs) {
-    NestedSetBuilder<Artifact> headerTokens = NestedSetBuilder.stableOrder();
-    for (OutputGroupInfo dep :
-        ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupInfo.SKYLARK_CONSTRUCTOR)) {
-      headerTokens.addTransitive(dep.getOutputGroup(CcCompilationHelper.HIDDEN_HEADER_TOKENS));
-    }
-    if (ruleContext.getFragment(CppConfiguration.class).processHeadersInDependencies()) {
-      headerTokens.addAll(ccCompilationOutputs.getHeaderTokenFiles());
-    }
-    return headerTokens.build();
-  }
-
   private TransitiveLipoInfoProvider collectTransitiveLipoInfo(CcCompilationOutputs outputs) {
     if (fdoSupport.getFdoSupport().getFdoRoot() == null) {
       return TransitiveLipoInfoProvider.EMPTY;
@@ -1086,25 +1236,912 @@
         : compilationOutputs.getTemps();
   }
 
-  public void registerAdditionalModuleMap(CppModuleMap cppModuleMap) {
-    this.additionalCppModuleMaps.add(Preconditions.checkNotNull(cppModuleMap));
+  /** @return whether this target needs to generate a pic header module. */
+  private boolean getGeneratesPicHeaderModule() {
+    return shouldProvideHeaderModules() && !fake && getGeneratePicActions();
   }
 
-  /** Don't generate a module map for this target if a custom module map is provided. */
-  public CcCompilationHelper doNotGenerateModuleMap() {
-    generateModuleMap = false;
-    return this;
+  /** @return whether this target needs to generate a non-pic header module. */
+  private boolean getGeneratesNoPicHeaderModule() {
+    return shouldProvideHeaderModules() && !fake && getGenerateNoPicActions();
+  }
+
+  /** @return whether we want to provide header modules for the current target. */
+  private boolean shouldProvideHeaderModules() {
+    return featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES)
+        && !cppConfiguration.isLipoContextCollector();
+  }
+
+  /** @return whether this target needs to generate non-pic actions. */
+  private boolean getGenerateNoPicActions() {
+    if (!generateNoPic) {
+      return false;
+    }
+    boolean picFeatureEnabled = featureConfiguration.isEnabled(CppRuleClasses.PIC);
+    boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, true);
+    boolean usePicForNonBinaries = CppHelper.usePic(ruleContext, ccToolchain, false);
+
+    if (!usePicForNonBinaries) {
+      // This means you have to be prepared to use non-pic output for dynamic libraries.
+      return true;
+    }
+
+    // Either you're only making a dynamic library (onlySingleOutput) or pic should be used
+    // in all cases.
+    if (usePicForBinaries) {
+      if (picFeatureEnabled) {
+        return false;
+      }
+      ruleContext.ruleError(PIC_CONFIGURATION_ERROR);
+    }
+
+    return true;
+  }
+
+  /** @return whether this target needs to generate pic actions. */
+  private boolean getGeneratePicActions() {
+    return featureConfiguration.isEnabled(CppRuleClasses.PIC)
+        && CppHelper.usePic(ruleContext, ccToolchain, false);
+  }
+
+  /** @return the non-pic header module artifact for the current target. */
+  private Artifact getHeaderModule(Artifact moduleMapArtifact) {
+    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
+    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
+    return ruleContext.getRelatedArtifact(outputName, ".pcm");
+  }
+
+  /** @return the pic header module artifact for the current target. */
+  private Artifact getPicHeaderModule(Artifact moduleMapArtifact) {
+    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
+    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
+    return ruleContext.getRelatedArtifact(outputName, ".pic.pcm");
   }
 
   /**
-   * Sets the purpose for the context.
-   *
-   * @see CppCompilationContext.Builder#setPurpose
-   * @param purpose must be a string which is suitable for use as a filename. A single rule may have
-   *     many middlemen with distinct purposes.
+   * Constructs the C++ compiler actions. It generally creates one action for every specified source
+   * file. It takes into account LIPO, fake-ness, coverage, and PIC, in addition to using the
+   * settings specified on the current object. This method should only be called once.
    */
-  public CcCompilationHelper setPurpose(@Nullable String purpose) {
-    this.purpose = purpose;
-    return this;
+  private CcCompilationOutputs createCcCompileActions() throws RuleErrorException {
+    CcCompilationOutputs.Builder result = new CcCompilationOutputs.Builder();
+    Preconditions.checkNotNull(cppCompilationContext);
+    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+
+    if (shouldProvideHeaderModules()) {
+      Label moduleMapLabel =
+          Label.parseAbsoluteUnchecked(cppCompilationContext.getCppModuleMap().getName());
+      Collection<Artifact> modules =
+          createModuleAction(result, cppCompilationContext.getCppModuleMap());
+      if (featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN)) {
+        for (Artifact module : modules) {
+          // TODO(djasper): Investigate whether we need to use a label separate from that of the
+          // module map. It is used for per-file-copts.
+          createModuleCodegenAction(result, moduleMapLabel, module);
+        }
+      }
+    } else if (cppCompilationContext.getVerificationModuleMap() != null) {
+      Collection<Artifact> modules =
+          createModuleAction(result, cppCompilationContext.getVerificationModuleMap());
+      for (Artifact module : modules) {
+        result.addHeaderTokenFile(module);
+      }
+    }
+
+    for (CppSource source : compilationUnitSources) {
+      Artifact sourceArtifact = source.getSource();
+      Label sourceLabel = source.getLabel();
+      String outputName =
+          FileSystemUtils.removeExtension(sourceArtifact.getRootRelativePath()).getPathString();
+      CppCompileActionBuilder builder = initializeCompileAction(sourceArtifact);
+
+      builder
+          .setSemantics(semantics)
+          .addMandatoryInputs(compilationMandatoryInputs)
+          .addAdditionalIncludeScanningRoots(additionalIncludeScanningRoots);
+
+      boolean bitcodeOutput =
+          featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
+              && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename());
+
+      if (!sourceArtifact.isTreeArtifact()) {
+        switch (source.getType()) {
+          case HEADER:
+            createHeaderAction(
+                sourceLabel, outputName, result, env, builder, isGenerateDotdFile(sourceArtifact));
+            break;
+          default:
+            createSourceAction(
+                sourceLabel,
+                outputName,
+                result,
+                env,
+                sourceArtifact,
+                builder,
+                // TODO(plf): Continue removing CLIF logic from C++. Follow up changes would include
+                // refactoring CppSource.Type and ArtifactCategory to be classes instead of enums
+                // that could be instantiated with arbitrary values.
+                source.getType() == CppSource.Type.CLIF_INPUT_PROTO
+                    ? ArtifactCategory.CLIF_OUTPUT_PROTO
+                    : ArtifactCategory.OBJECT_FILE,
+                cppCompilationContext.getCppModuleMap(),
+                /* addObject= */ true,
+                isCodeCoverageEnabled(),
+                // The source action does not generate dwo when it has bitcode
+                // output (since it isn't generating a native object with debug
+                // info). In that case the LtoBackendAction will generate the dwo.
+                CppHelper.shouldCreatePerObjectDebugInfo(
+                        cppConfiguration, ccToolchain, featureConfiguration)
+                    && !bitcodeOutput,
+                isGenerateDotdFile(sourceArtifact));
+            break;
+        }
+      } else {
+        switch (source.getType()) {
+          case HEADER:
+            Artifact headerTokenFile =
+                createCompileActionTemplate(
+                    env,
+                    source,
+                    builder,
+                    ImmutableList.of(
+                        ArtifactCategory.GENERATED_HEADER, ArtifactCategory.PROCESSED_HEADER),
+                    false);
+            result.addHeaderTokenFile(headerTokenFile);
+            break;
+          case SOURCE:
+            Artifact objectFile =
+                createCompileActionTemplate(
+                    env, source, builder, ImmutableList.of(ArtifactCategory.OBJECT_FILE), false);
+            result.addObjectFile(objectFile);
+
+            if (getGeneratePicActions()) {
+              Artifact picObjectFile =
+                  createCompileActionTemplate(
+                      env,
+                      source,
+                      builder,
+                      ImmutableList.of(ArtifactCategory.PIC_OBJECT_FILE),
+                      true);
+              result.addPicObjectFile(picObjectFile);
+            }
+            break;
+          default:
+            throw new IllegalStateException(
+                "Encountered invalid source types when creating CppCompileActionTemplates");
+        }
+      }
+    }
+
+    return result.build();
+  }
+
+  private Artifact createCompileActionTemplate(
+      AnalysisEnvironment env,
+      CppSource source,
+      CppCompileActionBuilder builder,
+      Iterable<ArtifactCategory> outputCategories,
+      boolean usePic) {
+    SpecialArtifact sourceArtifact = (SpecialArtifact) source.getSource();
+    SpecialArtifact outputFiles =
+        CppHelper.getCompileOutputTreeArtifact(ruleContext, sourceArtifact, usePic);
+    // TODO(rduan): Dotd file output is not supported yet.
+    builder.setOutputs(outputFiles, /* dotdFile= */ null);
+    setupCompileBuildVariables(
+        builder,
+        source.getLabel(),
+        usePic,
+        /* ccRelativeName= */ null,
+        /* autoFdoImportPath= */ null,
+        /* gcnoFile= */ null,
+        /* dwoFile= */ null,
+        /* ltoIndexingFile= */ null,
+        builder.getContext().getCppModuleMap());
+    semantics.finalizeCompileActionBuilder(ruleContext, builder);
+    // Make sure this builder doesn't reference ruleContext outside of analysis phase.
+    CppCompileActionTemplate actionTemplate =
+        new CppCompileActionTemplate(
+            sourceArtifact,
+            outputFiles,
+            builder,
+            ccToolchain,
+            outputCategories,
+            ruleContext.getActionOwner());
+    env.registerAction(actionTemplate);
+
+    return outputFiles;
+  }
+
+  private void setupCompileBuildVariables(
+      CppCompileActionBuilder builder,
+      Label sourceLabel,
+      boolean usePic,
+      PathFragment ccRelativeName,
+      PathFragment autoFdoImportPath,
+      Artifact gcnoFile,
+      Artifact dwoFile,
+      Artifact ltoIndexingFile,
+      CppModuleMap cppModuleMap) {
+    CcToolchainFeatures.Variables.Builder buildVariables =
+        new CcToolchainFeatures.Variables.Builder(ccToolchain.getBuildVariables());
+
+    CppCompilationContext builderContext = builder.getContext();
+    Artifact sourceFile = builder.getSourceFile();
+    Artifact outputFile = builder.getOutputFile();
+    String realOutputFilePath;
+
+    buildVariables.addStringVariable(SOURCE_FILE_VARIABLE_NAME, sourceFile.getExecPathString());
+    buildVariables.addStringVariable(OUTPUT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
+    buildVariables.addStringSequenceVariable(
+        USER_COMPILE_FLAGS_VARIABLE_NAME,
+        ImmutableList.<String>builder()
+            .addAll(copts)
+            .addAll(collectPerFileCopts(sourceFile, sourceLabel))
+            .build());
+
+    String sourceFilename = sourceFile.getExecPathString();
+    buildVariables.addLazyStringSequenceVariable(
+        LEGACY_COMPILE_FLAGS_VARIABLE_NAME,
+        getLegacyCompileFlagsSupplier(cppConfiguration, ccToolchain, sourceFilename, features));
+
+    if (!CppFileTypes.OBJC_SOURCE.matches(sourceFilename)
+        && !CppFileTypes.OBJCPP_SOURCE.matches(sourceFilename)) {
+      buildVariables.addLazyStringSequenceVariable(
+          UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME,
+          getUnfilteredCompileFlagsSupplier(ccToolchain, features));
+    }
+
+    if (builder.getTempOutputFile() != null) {
+      realOutputFilePath = builder.getTempOutputFile().getPathString();
+    } else {
+      realOutputFilePath = builder.getOutputFile().getExecPathString();
+    }
+
+    if (FileType.contains(outputFile, CppFileTypes.ASSEMBLER, CppFileTypes.PIC_ASSEMBLER)) {
+      buildVariables.addStringVariable(OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME, realOutputFilePath);
+    } else if (FileType.contains(
+        outputFile,
+        CppFileTypes.PREPROCESSED_C,
+        CppFileTypes.PREPROCESSED_CPP,
+        CppFileTypes.PIC_PREPROCESSED_C,
+        CppFileTypes.PIC_PREPROCESSED_CPP)) {
+      buildVariables.addStringVariable(OUTPUT_PREPROCESS_FILE_VARIABLE_NAME, realOutputFilePath);
+    } else {
+      buildVariables.addStringVariable(OUTPUT_OBJECT_FILE_VARIABLE_NAME, realOutputFilePath);
+    }
+
+    DotdFile dotdFile =
+        isGenerateDotdFile(sourceFile) ? Preconditions.checkNotNull(builder.getDotdFile()) : null;
+    // Set dependency_file to enable <object>.d file generation.
+    if (dotdFile != null) {
+      buildVariables.addStringVariable(
+          DEPENDENCY_FILE_VARIABLE_NAME, dotdFile.getSafeExecPath().getPathString());
+    }
+
+    if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS) && cppModuleMap != null) {
+      // If the feature is enabled and cppModuleMap is null, we are about to fail during analysis
+      // in any case, but don't crash.
+      buildVariables.addStringVariable(MODULE_NAME_VARIABLE_NAME, cppModuleMap.getName());
+      buildVariables.addStringVariable(
+          MODULE_MAP_FILE_VARIABLE_NAME, cppModuleMap.getArtifact().getExecPathString());
+      StringSequenceBuilder sequence = new StringSequenceBuilder();
+      for (Artifact artifact : builderContext.getDirectModuleMaps()) {
+        sequence.addValue(artifact.getExecPathString());
+      }
+      buildVariables.addCustomBuiltVariable(DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME, sequence);
+    }
+    if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES)) {
+      // Module inputs will be set later when the action is executed.
+      buildVariables.addStringSequenceVariable(MODULE_FILES_VARIABLE_NAME, ImmutableSet.of());
+    }
+    if (featureConfiguration.isEnabled(CppRuleClasses.INCLUDE_PATHS)) {
+      buildVariables.addStringSequenceVariable(
+          INCLUDE_PATHS_VARIABLE_NAME, getSafePathStrings(builderContext.getIncludeDirs()));
+      buildVariables.addStringSequenceVariable(
+          QUOTE_INCLUDE_PATHS_VARIABLE_NAME,
+          getSafePathStrings(builderContext.getQuoteIncludeDirs()));
+      buildVariables.addStringSequenceVariable(
+          SYSTEM_INCLUDE_PATHS_VARIABLE_NAME,
+          getSafePathStrings(builderContext.getSystemIncludeDirs()));
+    }
+
+    if (featureConfiguration.isEnabled(CppRuleClasses.PREPROCESSOR_DEFINES)) {
+      String fdoBuildStamp = CppHelper.getFdoBuildStamp(ruleContext, fdoSupport.getFdoSupport());
+      ImmutableList<String> defines;
+      if (fdoBuildStamp != null) {
+        // Stamp FDO builds with FDO subtype string
+        defines =
+            ImmutableList.<String>builder()
+                .addAll(builderContext.getDefines())
+                .add(
+                    CppConfiguration.FDO_STAMP_MACRO
+                        + "=\""
+                        + CppHelper.getFdoBuildStamp(ruleContext, fdoSupport.getFdoSupport())
+                        + "\"")
+                .build();
+      } else {
+        defines = builderContext.getDefines();
+      }
+
+      buildVariables.addStringSequenceVariable(PREPROCESSOR_DEFINES_VARIABLE_NAME, defines);
+    }
+
+    if (usePic) {
+      if (!featureConfiguration.isEnabled(CppRuleClasses.PIC)) {
+        ruleContext.ruleError(PIC_CONFIGURATION_ERROR);
+      }
+      buildVariables.addStringVariable(PIC_VARIABLE_NAME, "");
+    }
+
+    if (ccRelativeName != null) {
+      fdoSupport
+          .getFdoSupport()
+          .configureCompilation(
+              builder,
+              buildVariables,
+              ruleContext,
+              ccRelativeName,
+              autoFdoImportPath,
+              usePic,
+              featureConfiguration,
+              fdoSupport);
+    }
+    if (gcnoFile != null) {
+      buildVariables.addStringVariable(GCOV_GCNO_FILE_VARIABLE_NAME, gcnoFile.getExecPathString());
+    }
+
+    if (dwoFile != null) {
+      buildVariables.addStringVariable(
+          PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME, dwoFile.getExecPathString());
+    }
+
+    if (ltoIndexingFile != null) {
+      buildVariables.addStringVariable(
+          LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME, ltoIndexingFile.getExecPathString());
+    }
+
+    for (VariablesExtension extension : variablesExtensions) {
+      extension.addVariables(buildVariables);
+    }
+
+    CcToolchainFeatures.Variables variables = buildVariables.build();
+    builder.setVariables(variables);
+  }
+
+  /**
+   * Returns a {@code CppCompileActionBuilder} with the common fields for a C++ compile action being
+   * initialized.
+   */
+  private CppCompileActionBuilder initializeCompileAction(Artifact sourceArtifact) {
+    CppCompileActionBuilder builder = createCompileActionBuilder(sourceArtifact);
+    builder.setFeatureConfiguration(featureConfiguration);
+
+    return builder;
+  }
+
+  /**
+   * Creates a basic cpp compile action builder for source file. Configures options, crosstool
+   * inputs, output and dotd file names, compilation context and copts.
+   */
+  private CppCompileActionBuilder createCompileActionBuilder(Artifact source) {
+    CppCompileActionBuilder builder =
+        new CppCompileActionBuilder(ruleContext, ccToolchain, configuration);
+    builder.setSourceFile(source);
+    builder.setContext(cppCompilationContext);
+    builder.addEnvironment(ccToolchain.getEnvironment());
+    builder.setCoptsFilter(coptsFilter);
+    return builder;
+  }
+
+  private void createModuleCodegenAction(
+      CcCompilationOutputs.Builder result, Label sourceLabel, Artifact module)
+      throws RuleErrorException {
+    if (fake) {
+      // We can't currently foresee a situation where we'd want nocompile tests for module codegen.
+      // If we find one, support needs to be added here.
+      return;
+    }
+    String outputName = module.getRootRelativePath().getPathString();
+
+    // TODO(djasper): Make this less hacky after refactoring how the PIC/noPIC actions are created.
+    boolean pic = module.getFilename().contains(".pic.");
+
+    CppCompileActionBuilder builder = initializeCompileAction(module);
+    builder.setSemantics(semantics);
+    builder.setPicMode(pic);
+    builder.setOutputs(
+        ruleContext, ArtifactCategory.OBJECT_FILE, outputName, isGenerateDotdFile(module));
+    PathFragment ccRelativeName = module.getRootRelativePath();
+
+    String gcnoFileName =
+        CppHelper.getArtifactNameForCategory(
+            ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName);
+    // TODO(djasper): This is now duplicated. Refactor the various create..Action functions.
+    Artifact gcnoFile =
+        isCodeCoverageEnabled() && !CppHelper.isLipoOptimization(cppConfiguration, ccToolchain)
+            ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
+            : null;
+
+    boolean generateDwo =
+        CppHelper.shouldCreatePerObjectDebugInfo(
+            cppConfiguration, ccToolchain, featureConfiguration);
+    Artifact dwoFile = generateDwo ? getDwoFile(builder.getOutputFile()) : null;
+    // TODO(tejohnson): Add support for ThinLTO if needed.
+    boolean bitcodeOutput =
+        featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
+            && CppFileTypes.LTO_SOURCE.matches(module.getFilename());
+    Preconditions.checkState(!bitcodeOutput);
+
+    setupCompileBuildVariables(
+        builder,
+        sourceLabel,
+        /* usePic= */ pic,
+        ccRelativeName,
+        module.getExecPath(),
+        gcnoFile,
+        dwoFile,
+        /* ltoIndexingFile= */ null,
+        builder.getContext().getCppModuleMap());
+
+    builder.setGcnoFile(gcnoFile);
+    builder.setDwoFile(dwoFile);
+
+    semantics.finalizeCompileActionBuilder(ruleContext, builder);
+    CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
+    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+    env.registerAction(compileAction);
+    Artifact objectFile = compileAction.getOutputFile();
+    if (pic) {
+      result.addPicObjectFile(objectFile);
+    } else {
+      result.addObjectFile(objectFile);
+    }
+  }
+
+  /** Returns true if Dotd file should be generated. */
+  private boolean isGenerateDotdFile(Artifact sourceArtifact) {
+    return CppFileTypes.headerDiscoveryRequired(sourceArtifact)
+        && !featureConfiguration.isEnabled(CppRuleClasses.PARSE_SHOWINCLUDES);
+  }
+
+  private void createHeaderAction(
+      Label sourceLabel,
+      String outputName,
+      CcCompilationOutputs.Builder result,
+      AnalysisEnvironment env,
+      CppCompileActionBuilder builder,
+      boolean generateDotd)
+      throws RuleErrorException {
+    String outputNameBase =
+        CppHelper.getArtifactNameForCategory(
+            ruleContext, ccToolchain, ArtifactCategory.GENERATED_HEADER, outputName);
+
+    builder
+        .setOutputs(ruleContext, ArtifactCategory.PROCESSED_HEADER, outputNameBase, generateDotd)
+        // If we generate pic actions, we prefer the header actions to use the pic artifacts.
+        .setPicMode(getGeneratePicActions());
+    setupCompileBuildVariables(
+        builder,
+        sourceLabel,
+        this.getGeneratePicActions(),
+        /* ccRelativeName= */ null,
+        /* autoFdoImportPath= */ null,
+        /* gcnoFile= */ null,
+        /* dwoFile= */ null,
+        /* ltoIndexingFile= */ null,
+        builder.getContext().getCppModuleMap());
+    semantics.finalizeCompileActionBuilder(ruleContext, builder);
+    CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
+    env.registerAction(compileAction);
+    Artifact tokenFile = compileAction.getOutputFile();
+    result.addHeaderTokenFile(tokenFile);
+  }
+
+  private Collection<Artifact> createModuleAction(
+      CcCompilationOutputs.Builder result, CppModuleMap cppModuleMap) throws RuleErrorException {
+    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+    Artifact moduleMapArtifact = cppModuleMap.getArtifact();
+    CppCompileActionBuilder builder = initializeCompileAction(moduleMapArtifact);
+
+    builder.setSemantics(semantics);
+
+    // A header module compile action is just like a normal compile action, but:
+    // - the compiled source file is the module map
+    // - it creates a header module (.pcm file).
+    return createSourceAction(
+        Label.parseAbsoluteUnchecked(cppModuleMap.getName()),
+        FileSystemUtils.removeExtension(moduleMapArtifact.getRootRelativePath()).getPathString(),
+        result,
+        env,
+        moduleMapArtifact,
+        builder,
+        ArtifactCategory.CPP_MODULE,
+        cppModuleMap,
+        /* addObject= */ false,
+        /* enableCoverage= */ false,
+        /* generateDwo= */ false,
+        isGenerateDotdFile(moduleMapArtifact));
+  }
+
+  private Collection<Artifact> createSourceAction(
+      Label sourceLabel,
+      String outputName,
+      CcCompilationOutputs.Builder result,
+      AnalysisEnvironment env,
+      Artifact sourceArtifact,
+      CppCompileActionBuilder builder,
+      ArtifactCategory outputCategory,
+      CppModuleMap cppModuleMap,
+      boolean addObject,
+      boolean enableCoverage,
+      boolean generateDwo,
+      boolean generateDotd)
+      throws RuleErrorException {
+    ImmutableList.Builder<Artifact> directOutputs = new ImmutableList.Builder<>();
+    PathFragment ccRelativeName = sourceArtifact.getRootRelativePath();
+    if (CppHelper.isLipoOptimization(cppConfiguration, ccToolchain)) {
+      // TODO(bazel-team): we shouldn't be needing this, merging context with the binary
+      // is a superset of necessary information.
+      LipoContextProvider lipoProvider =
+          Preconditions.checkNotNull(CppHelper.getLipoContextProvider(ruleContext), outputName);
+      builder.setContext(
+          CppCompilationContext.mergeForLipo(lipoProvider.getLipoContext(), cppCompilationContext));
+    }
+    boolean generatePicAction = getGeneratePicActions();
+    boolean generateNoPicAction = getGenerateNoPicActions();
+    Preconditions.checkState(generatePicAction || generateNoPicAction);
+    if (fake) {
+      boolean usePic = !generateNoPicAction;
+      createFakeSourceAction(
+          sourceLabel,
+          outputName,
+          result,
+          env,
+          builder,
+          outputCategory,
+          addObject,
+          ccRelativeName,
+          sourceArtifact.getExecPath(),
+          usePic,
+          generateDotd);
+    } else {
+      boolean bitcodeOutput =
+          featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
+              && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename());
+
+      // Create PIC compile actions (same as non-PIC, but use -fPIC and
+      // generate .pic.o, .pic.d, .pic.gcno instead of .o, .d, .gcno.)
+      if (generatePicAction) {
+        String picOutputBase =
+            CppHelper.getArtifactNameForCategory(
+                ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, outputName);
+        CppCompileActionBuilder picBuilder =
+            copyAsPicBuilder(builder, picOutputBase, outputCategory, generateDotd);
+        String gcnoFileName =
+            CppHelper.getArtifactNameForCategory(
+                ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, picOutputBase);
+        Artifact gcnoFile =
+            enableCoverage
+                ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
+                : null;
+        Artifact dwoFile = generateDwo ? getDwoFile(picBuilder.getOutputFile()) : null;
+        Artifact ltoIndexingFile =
+            bitcodeOutput ? getLtoIndexingFile(picBuilder.getOutputFile()) : null;
+
+        setupCompileBuildVariables(
+            picBuilder,
+            sourceLabel,
+            /* usePic= */ true,
+            ccRelativeName,
+            sourceArtifact.getExecPath(),
+            gcnoFile,
+            dwoFile,
+            ltoIndexingFile,
+            cppModuleMap);
+
+        result.addTemps(
+            createTempsActions(
+                sourceArtifact,
+                sourceLabel,
+                outputName,
+                picBuilder,
+                /* usePic= */ true,
+                /* generateDotd= */ generateDotd,
+                ccRelativeName));
+
+        picBuilder.setGcnoFile(gcnoFile);
+        picBuilder.setDwoFile(dwoFile);
+        picBuilder.setLtoIndexingFile(ltoIndexingFile);
+
+        semantics.finalizeCompileActionBuilder(ruleContext, picBuilder);
+        CppCompileAction picAction = picBuilder.buildOrThrowRuleError(ruleContext);
+        env.registerAction(picAction);
+        directOutputs.add(picAction.getOutputFile());
+        if (addObject) {
+          result.addPicObjectFile(picAction.getOutputFile());
+
+          if (bitcodeOutput) {
+            result.addLtoBitcodeFile(picAction.getOutputFile(), ltoIndexingFile);
+          }
+        }
+        if (dwoFile != null) {
+          // Host targets don't produce .dwo files.
+          result.addPicDwoFile(dwoFile);
+        }
+        if (cppConfiguration.isLipoContextCollector() && !generateNoPicAction) {
+          result.addLipoScannable(picAction);
+        }
+      }
+
+      if (generateNoPicAction) {
+        Artifact noPicOutputFile =
+            CppHelper.getCompileOutputArtifact(
+                ruleContext,
+                CppHelper.getArtifactNameForCategory(
+                    ruleContext, ccToolchain, outputCategory, outputName),
+                configuration);
+        builder.setOutputs(ruleContext, outputCategory, outputName, generateDotd);
+        String gcnoFileName =
+            CppHelper.getArtifactNameForCategory(
+                ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName);
+
+        // Create non-PIC compile actions
+        Artifact gcnoFile =
+            !CppHelper.isLipoOptimization(cppConfiguration, ccToolchain) && enableCoverage
+                ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
+                : null;
+
+        Artifact noPicDwoFile = generateDwo ? getDwoFile(noPicOutputFile) : null;
+        Artifact ltoIndexingFile =
+            bitcodeOutput ? getLtoIndexingFile(builder.getOutputFile()) : null;
+
+        setupCompileBuildVariables(
+            builder,
+            sourceLabel,
+            /* usePic= */ false,
+            ccRelativeName,
+            sourceArtifact.getExecPath(),
+            gcnoFile,
+            noPicDwoFile,
+            ltoIndexingFile,
+            cppModuleMap);
+
+        result.addTemps(
+            createTempsActions(
+                sourceArtifact,
+                sourceLabel,
+                outputName,
+                builder,
+                /* usePic= */ false,
+                generateDotd,
+                ccRelativeName));
+
+        builder.setGcnoFile(gcnoFile);
+        builder.setDwoFile(noPicDwoFile);
+        builder.setLtoIndexingFile(ltoIndexingFile);
+
+        semantics.finalizeCompileActionBuilder(ruleContext, builder);
+        CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
+        env.registerAction(compileAction);
+        Artifact objectFile = compileAction.getOutputFile();
+        directOutputs.add(objectFile);
+        if (addObject) {
+          result.addObjectFile(objectFile);
+          if (bitcodeOutput) {
+            result.addLtoBitcodeFile(objectFile, ltoIndexingFile);
+          }
+        }
+        if (noPicDwoFile != null) {
+          // Host targets don't produce .dwo files.
+          result.addDwoFile(noPicDwoFile);
+        }
+        if (cppConfiguration.isLipoContextCollector()) {
+          result.addLipoScannable(compileAction);
+        }
+      }
+    }
+    return directOutputs.build();
+  }
+
+  /**
+   * Creates cpp PIC compile action builder from the given builder by adding necessary copt and
+   * changing output and dotd file names.
+   */
+  private CppCompileActionBuilder copyAsPicBuilder(
+      CppCompileActionBuilder builder,
+      String outputName,
+      ArtifactCategory outputCategory,
+      boolean generateDotd)
+      throws RuleErrorException {
+    CppCompileActionBuilder picBuilder = new CppCompileActionBuilder(builder);
+    picBuilder.setPicMode(true).setOutputs(ruleContext, outputCategory, outputName, generateDotd);
+
+    return picBuilder;
+  }
+
+  String getOutputNameBaseWith(String base, boolean usePic) throws RuleErrorException {
+    return usePic
+        ? CppHelper.getArtifactNameForCategory(
+            ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, base)
+        : base;
+  }
+
+  private void createFakeSourceAction(
+      Label sourceLabel,
+      String outputName,
+      CcCompilationOutputs.Builder result,
+      AnalysisEnvironment env,
+      CppCompileActionBuilder builder,
+      ArtifactCategory outputCategory,
+      boolean addObject,
+      PathFragment ccRelativeName,
+      PathFragment execPath,
+      boolean usePic,
+      boolean generateDotd)
+      throws RuleErrorException {
+    String outputNameBase = getOutputNameBaseWith(outputName, usePic);
+    String tempOutputName =
+        ruleContext
+            .getConfiguration()
+            .getBinFragment()
+            .getRelative(CppHelper.getObjDirectory(ruleContext.getLabel()))
+            .getRelative(
+                CppHelper.getArtifactNameForCategory(
+                    ruleContext,
+                    ccToolchain,
+                    outputCategory,
+                    getOutputNameBaseWith(outputName + ".temp", usePic)))
+            .getPathString();
+    builder
+        .setPicMode(usePic)
+        .setOutputs(ruleContext, outputCategory, outputNameBase, generateDotd)
+        .setTempOutputFile(PathFragment.create(tempOutputName));
+
+    setupCompileBuildVariables(
+        builder,
+        sourceLabel,
+        usePic,
+        ccRelativeName,
+        execPath,
+        /* gcnoFile= */ null,
+        /* dwoFile= */ null,
+        /* ltoIndexingFile= */ null,
+        builder.getContext().getCppModuleMap());
+    semantics.finalizeCompileActionBuilder(ruleContext, builder);
+    CppCompileAction action = builder.buildOrThrowRuleError(ruleContext);
+    env.registerAction(action);
+    if (addObject) {
+      if (usePic) {
+        result.addPicObjectFile(action.getOutputFile());
+      } else {
+        result.addObjectFile(action.getOutputFile());
+      }
+    }
+  }
+
+  /** Returns true iff code coverage is enabled for the given target. */
+  private boolean isCodeCoverageEnabled() {
+    if (configuration.isCodeCoverageEnabled()) {
+      // If rule is matched by the instrumentation filter, enable instrumentation
+      if (InstrumentedFilesCollector.shouldIncludeLocalSources(ruleContext)) {
+        return true;
+      }
+      // At this point the rule itself is not matched by the instrumentation filter. However, we
+      // might still want to instrument C++ rules if one of the targets listed in "deps" is
+      // instrumented and, therefore, can supply header files that we would want to collect code
+      // coverage for. For example, think about cc_test rule that tests functionality defined in a
+      // header file that is supplied by the cc_library.
+      //
+      // Note that we only check direct prerequisites and not the transitive closure. This is done
+      // for two reasons:
+      // a) It is a good practice to declare libraries which you directly rely on. Including headers
+      //    from a library hidden deep inside the transitive closure makes build dependencies less
+      //    readable and can lead to unexpected breakage.
+      // b) Traversing the transitive closure for each C++ compile action would require more complex
+      //    implementation (with caching results of this method) to avoid O(N^2) slowdown.
+      if (ruleContext.getRule().isAttrDefined("deps", BuildType.LABEL_LIST)) {
+        for (TransitiveInfoCollection dep : ruleContext.getPrerequisites("deps", Mode.TARGET)) {
+          if (dep.getProvider(CppCompilationContext.class) != null
+              && InstrumentedFilesCollector.shouldIncludeLocalSources(configuration, dep)) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  private ImmutableList<String> collectPerFileCopts(Artifact sourceFile, Label sourceLabel) {
+    return cppConfiguration
+        .getPerFileCopts()
+        .stream()
+        .filter(
+            perLabelOptions ->
+                (sourceLabel != null && perLabelOptions.isIncluded(sourceLabel))
+                    || perLabelOptions.isIncluded(sourceFile))
+        .map(PerLabelOptions::getOptions)
+        .flatMap(options -> options.stream())
+        .collect(ImmutableList.toImmutableList());
+  }
+
+  /** Get the safe path strings for a list of paths to use in the build variables. */
+  private ImmutableSet<String> getSafePathStrings(Collection<PathFragment> paths) {
+    ImmutableSet.Builder<String> result = ImmutableSet.builder();
+    for (PathFragment path : paths) {
+      result.add(path.getSafePathString());
+    }
+    return result.build();
+  }
+
+  private Artifact getDwoFile(Artifact outputFile) {
+    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ".dwo");
+  }
+
+  private Artifact getLtoIndexingFile(Artifact outputFile) {
+    String ext = Iterables.getOnlyElement(CppFileTypes.LTO_INDEXING_OBJECT_FILE.getExtensions());
+    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ext);
+  }
+
+  /** Create the actions for "--save_temps". */
+  private ImmutableList<Artifact> createTempsActions(
+      Artifact source,
+      Label sourceLabel,
+      String outputName,
+      CppCompileActionBuilder builder,
+      boolean usePic,
+      boolean generateDotd,
+      PathFragment ccRelativeName)
+      throws RuleErrorException {
+    if (!cppConfiguration.getSaveTemps()) {
+      return ImmutableList.of();
+    }
+
+    String path = source.getFilename();
+    boolean isCFile = CppFileTypes.C_SOURCE.matches(path);
+    boolean isCppFile = CppFileTypes.CPP_SOURCE.matches(path);
+
+    if (!isCFile && !isCppFile) {
+      return ImmutableList.of();
+    }
+
+    ArtifactCategory category =
+        isCFile ? ArtifactCategory.PREPROCESSED_C_SOURCE : ArtifactCategory.PREPROCESSED_CPP_SOURCE;
+
+    String outputArtifactNameBase = getOutputNameBaseWith(outputName, usePic);
+
+    CppCompileActionBuilder dBuilder = new CppCompileActionBuilder(builder);
+    dBuilder.setOutputs(ruleContext, category, outputArtifactNameBase, generateDotd);
+    setupCompileBuildVariables(
+        dBuilder,
+        sourceLabel,
+        usePic,
+        ccRelativeName,
+        source.getExecPath(),
+        /* gcnoFile= */ null,
+        /* dwoFile= */ null,
+        /* ltoIndexingFile= */ null,
+        builder.getContext().getCppModuleMap());
+    semantics.finalizeCompileActionBuilder(ruleContext, dBuilder);
+    CppCompileAction dAction = dBuilder.buildOrThrowRuleError(ruleContext);
+    ruleContext.registerAction(dAction);
+
+    CppCompileActionBuilder sdBuilder = new CppCompileActionBuilder(builder);
+    sdBuilder.setOutputs(
+        ruleContext, ArtifactCategory.GENERATED_ASSEMBLY, outputArtifactNameBase, generateDotd);
+    setupCompileBuildVariables(
+        sdBuilder,
+        sourceLabel,
+        usePic,
+        ccRelativeName,
+        source.getExecPath(),
+        /* gcnoFile= */ null,
+        /* dwoFile= */ null,
+        /* ltoIndexingFile= */ null,
+        builder.getContext().getCppModuleMap());
+    semantics.finalizeCompileActionBuilder(ruleContext, sdBuilder);
+    CppCompileAction sdAction = sdBuilder.buildOrThrowRuleError(ruleContext);
+    ruleContext.registerAction(sdAction);
+
+    return ImmutableList.of(dAction.getOutputFile(), sdAction.getOutputFile());
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index d07dd05..660eff3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -202,7 +202,7 @@
                                    + "Did you mean to use 'linkstatic=1' instead?");
     }
 
-    linkingHelper.setCreateDynamicLibrary(createDynamicLibrary);
+    linkingHelper.setShouldCreateDynamicLibrary(createDynamicLibrary);
     linkingHelper.setDynamicLibrary(soImplArtifact);
 
     // If the reason we're not creating a dynamic library is that the toolchain
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
index 77dc80f..0d96ff1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.rules.cpp;
 
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 import static java.util.stream.Collectors.joining;
 
 import com.google.common.base.Preconditions;
@@ -23,6 +24,8 @@
 import com.google.common.collect.Sets;
 import com.google.common.collect.Streams;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FailAction;
+import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
 import com.google.devtools.build.lib.analysis.AnalysisUtils;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.LanguageDependentFragment;
@@ -38,13 +41,17 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
-import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
+import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
 import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
+import com.google.devtools.build.lib.rules.cpp.Link.Picness;
 import com.google.devtools.build.lib.rules.cpp.Link.Staticness;
 import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
 import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -54,7 +61,7 @@
 /**
  * A class to create C/C++ link actions in a way that is consistent with cc_library. Rules that
  * generate source files and emulate cc_library on top of that should use this class instead of the
- * lower-level APIs in CppHelper and CppModel.
+ * lower-level APIs in CppHelper and CppLinkActionBuilder.
  *
  * <p>Rules that want to use this class are required to have implicit dependencies on the toolchain,
  * the STL, the lipo context, and so on. Optionally, they can also have copts, and malloc
@@ -133,17 +140,18 @@
   private final RuleContext ruleContext;
   private final CppSemantics semantics;
   private final BuildConfiguration configuration;
+  private final CppConfiguration cppConfiguration;
 
   private final List<Artifact> nonCodeLinkerInputs = new ArrayList<>();
   private final List<String> linkopts = new ArrayList<>();
   private final List<TransitiveInfoCollection> deps = new ArrayList<>();
   private final NestedSetBuilder<Artifact> linkstamps = NestedSetBuilder.stableOrder();
   private final List<Artifact> linkActionInputs = new ArrayList<>();
+  private CppCompilationContext cppCompilationContext;
 
   @Nullable private Artifact dynamicLibrary;
   private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY;
   private boolean neverlink;
-  private boolean fake;
 
   private final List<LibraryToLink> staticLibraries = new ArrayList<>();
   private final List<LibraryToLink> picStaticLibraries = new ArrayList<>();
@@ -155,8 +163,8 @@
   private boolean emitCcNativeLibrariesProvider;
   private boolean emitCcSpecificLinkParamsProvider;
   private boolean emitInterfaceSharedObjects;
-  private boolean createDynamicLibrary = true;
-  private boolean createStaticLibraries = true;
+  private boolean shouldCreateDynamicLibrary = true;
+  private boolean shouldCreateStaticLibraries = true;
   private final List<VariablesExtension> variablesExtensions = new ArrayList<>();
 
   private final FeatureConfiguration featureConfiguration;
@@ -187,6 +195,8 @@
     this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
     this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
     this.configuration = Preconditions.checkNotNull(configuration);
+    this.cppConfiguration =
+        Preconditions.checkNotNull(ruleContext.getFragment(CppConfiguration.class));
   }
 
   /** Sets fields that overlap for cc_library and cc_binary rules. */
@@ -338,17 +348,6 @@
     return this;
   }
 
-  /**
-   * Marks the resulting code as fake, i.e., the code will not actually be compiled or linked, but
-   * instead, the compile command is written to a file and added to the runfiles. This is currently
-   * used for non-compilation tests. Unfortunately, the design is problematic, so please don't add
-   * any further uses.
-   */
-  public CcLinkingHelper setFake(boolean fake) {
-    this.fake = fake;
-    return this;
-  }
-
   /*
    * Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule
    * labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may
@@ -403,14 +402,16 @@
    * generate a dynamic library. Note that the selection between dynamic or static linking is
    * performed at the binary rule level.
    */
-  public CcLinkingHelper setCreateDynamicLibrary(boolean emitDynamicLibrary) {
-    this.createDynamicLibrary = emitDynamicLibrary;
+  public CcLinkingHelper setShouldCreateDynamicLibrary(boolean emitDynamicLibrary) {
+    this.shouldCreateDynamicLibrary = emitDynamicLibrary;
     return this;
   }
 
-  /** When createStaticLibraries is true, there are no actions created for static libraries. */
-  public CcLinkingHelper setCreateStaticLibraries(boolean emitStaticLibraries) {
-    this.createStaticLibraries = emitStaticLibraries;
+  /**
+   * When shouldCreateStaticLibraries is true, there are no actions created for static libraries.
+   */
+  public CcLinkingHelper setShouldCreateStaticLibraries(boolean emitStaticLibraries) {
+    this.shouldCreateStaticLibraries = emitStaticLibraries;
     return this;
   }
 
@@ -438,8 +439,7 @@
       }
     }
 
-    CppModel model = initializeCppModel();
-    model.setContext(cppCompilationContext);
+    this.cppCompilationContext = cppCompilationContext;
 
     // Create link actions (only if there are object files or if explicitly requested).
     CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY;
@@ -452,7 +452,7 @@
       // generate any link actions, effectively disabling header checking in some cases.
       if (linkType.staticness() == Staticness.STATIC) {
         // TODO(bazel-team): This can't create the link action for a cc_binary yet.
-        ccLinkingOutputs = model.createCcLinkActions(ccOutputs, nonCodeLinkerInputs);
+        ccLinkingOutputs = createCcLinkActions(ccOutputs, nonCodeLinkerInputs);
       }
     }
     CcLinkingOutputs originalLinkingOutputs = ccLinkingOutputs;
@@ -606,34 +606,6 @@
     outputGroups.put(DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME, dynamicLibrary.build());
   }
 
-  /** Creates the C/C++ compilation action creator. */
-  private CppModel initializeCppModel() {
-    // TODO(plf): Split CppModel into compilation and linking and stop passing last two arguments.
-    return new CppModel(
-            ruleContext,
-            semantics,
-            ccToolchain,
-            fdoSupport,
-            configuration,
-            ImmutableList.of(),
-            CoptsFilter.alwaysPasses())
-        .setLinkTargetType(linkType)
-        .setNeverLink(neverlink)
-        .addLinkActionInputs(linkActionInputs)
-        .setFake(fake)
-        .setAllowInterfaceSharedObjects(emitInterfaceSharedObjects)
-        .setCreateDynamicLibrary(createDynamicLibrary)
-        .setCreateStaticLibraries(createStaticLibraries)
-        // Note: this doesn't actually save the temps, it just makes the CppModel use the
-        // configurations --save_temps setting to decide whether to actually save the temps.
-        .setSaveTemps(true)
-        .setDynamicLibrary(dynamicLibrary)
-        .addLinkopts(linkopts)
-        .setFeatureConfiguration(featureConfiguration)
-        .addVariablesExtension(variablesExtensions)
-        .setLinkedArtifactNameSuffix(linkedArtifactNameSuffix);
-  }
-
   private Runfiles collectCppRunfiles(
       CcLinkingOutputs ccLinkingOutputs, boolean linkingStatically) {
     Runfiles.Builder builder =
@@ -703,4 +675,356 @@
         ? CcExecutionDynamicLibrariesProvider.EMPTY
         : new CcExecutionDynamicLibrariesProvider(builder.build());
   }
+
+  /**
+   * Constructs the C++ linker actions. It generally generates two actions, one for a static library
+   * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
+   * it additionally creates a third action to generate a PIC static library. If PIC is required for
+   * shared libraries and binaries, then only PIC actions are registered.
+   *
+   * <p>For dynamic libraries, this method can additionally create an interface shared library that
+   * can be used for linking, but doesn't contain any executable code. This increases the number of
+   * cache hits for link actions. Call {@link #enableInterfaceSharedObjects()} to enable this
+   * behavior.
+   *
+   * @throws RuleErrorException
+   */
+  private CcLinkingOutputs createCcLinkActions(
+      CcCompilationOutputs ccOutputs, Iterable<Artifact> nonCodeLinkerInputs)
+      throws RuleErrorException, InterruptedException {
+    // For now only handle static links. Note that the dynamic library link below ignores linkType.
+    // TODO(bazel-team): Either support non-static links or move this check to setStaticLinkType().
+    Preconditions.checkState(
+        linkType.staticness() == Staticness.STATIC, "can only handle static links");
+
+    CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder();
+    if (cppConfiguration.isLipoContextCollector()) {
+      // Don't try to create LIPO link actions in collector mode,
+      // because it needs some data that's not available at this point.
+      return result.build();
+    }
+    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+    boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ true);
+    boolean usePicForSharedLibs =
+        CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ false);
+
+    PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName());
+    String libraryIdentifier =
+        ruleContext
+            .getPackageDirectory()
+            .getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
+            .getPathString();
+
+    if (shouldCreateStaticLibraries) {
+      createStaticLibraries(
+          result,
+          env,
+          usePicForBinaries,
+          usePicForSharedLibs,
+          libraryIdentifier,
+          ccOutputs,
+          nonCodeLinkerInputs);
+    }
+
+    if (shouldCreateDynamicLibrary) {
+      createDynamicLibrary(result, env, usePicForSharedLibs, libraryIdentifier, ccOutputs);
+    }
+
+    return result.build();
+  }
+
+  private void createStaticLibraries(
+      CcLinkingOutputs.Builder result,
+      AnalysisEnvironment env,
+      boolean usePicForBinaries,
+      boolean usePicForSharedLibs,
+      String libraryIdentifier,
+      CcCompilationOutputs ccOutputs,
+      Iterable<Artifact> nonCodeLinkerInputs)
+      throws RuleErrorException, InterruptedException {
+    // Create static library (.a). The linkType only reflects whether the library is alwayslink or
+    // not. The PIC-ness is determined by whether we need to use PIC or not. There are three cases
+    // for (usePicForSharedLibs usePicForBinaries):
+    //
+    // (1) (false false) -> no pic code
+    // (2) (true false)  -> shared libraries as pic, but not binaries
+    // (3) (true true)   -> both shared libraries and binaries as pic
+    //
+    // In case (3), we always need PIC, so only create one static library containing the PIC
+    // object
+    // files. The name therefore does not match the content.
+    //
+    // Presumably, it is done this way because the .a file is an implicit output of every
+    // cc_library
+    // rule, so we can't use ".pic.a" that in the always-PIC case.
+
+    // If the crosstool is configured to select an output artifact, we use that selection.
+    // Otherwise, we use linux defaults.
+    Artifact linkedArtifact = getLinkedArtifact(linkType);
+
+    CppLinkAction maybePicAction =
+        newLinkActionBuilder(linkedArtifact)
+            .addObjectFiles(ccOutputs.getObjectFiles(usePicForBinaries))
+            .addNonCodeInputs(nonCodeLinkerInputs)
+            .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
+            .setLinkType(linkType)
+            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
+            .addActionInputs(linkActionInputs)
+            .setLibraryIdentifier(libraryIdentifier)
+            .addVariablesExtensions(variablesExtensions)
+            .build();
+    env.registerAction(maybePicAction);
+    if (usePicForBinaries) {
+      result.addPicStaticLibrary(maybePicAction.getOutputLibrary());
+    } else {
+      result.addStaticLibrary(maybePicAction.getOutputLibrary());
+      // Create a second static library (.pic.a). Only in case (2) do we need both PIC and non-PIC
+      // static libraries. In that case, the first static library contains the non-PIC code, and
+      // this
+      // one contains the PIC code, so the names match the content.
+      if (usePicForSharedLibs) {
+        LinkTargetType picLinkType =
+            (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY)
+                ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY
+                : LinkTargetType.PIC_STATIC_LIBRARY;
+
+        // If the crosstool is configured to select an output artifact, we use that selection.
+        // Otherwise, we use linux defaults.
+        Artifact picArtifact = getLinkedArtifact(picLinkType);
+        CppLinkAction picAction =
+            newLinkActionBuilder(picArtifact)
+                .addObjectFiles(ccOutputs.getObjectFiles(/* usePic= */ true))
+                .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
+                .setLinkType(picLinkType)
+                .setLinkStaticness(LinkStaticness.FULLY_STATIC)
+                .addActionInputs(linkActionInputs)
+                .setLibraryIdentifier(libraryIdentifier)
+                .addVariablesExtensions(variablesExtensions)
+                .build();
+        env.registerAction(picAction);
+        result.addPicStaticLibrary(picAction.getOutputLibrary());
+      }
+    }
+  }
+
+  private void createDynamicLibrary(
+      CcLinkingOutputs.Builder result,
+      AnalysisEnvironment env,
+      boolean usePicForSharedLibs,
+      String libraryIdentifier,
+      CcCompilationOutputs ccOutputs)
+      throws RuleErrorException, InterruptedException {
+    // Create dynamic library.
+    Artifact soImpl;
+    String mainLibraryIdentifier;
+    if (dynamicLibrary == null) {
+      // If the crosstool is configured to select an output artifact, we use that selection.
+      // Otherwise, we use linux defaults.
+      soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY);
+      mainLibraryIdentifier = libraryIdentifier;
+    } else {
+      // This branch is only used for vestigial Google-internal rules where the name of the output
+      // file is explicitly specified in the BUILD file and as such, is platform-dependent. Thus,
+      // we just hardcode some reasonable logic to compute the library identifier and hope that this
+      // will eventually go away.
+      soImpl = dynamicLibrary;
+      mainLibraryIdentifier =
+          FileSystemUtils.removeExtension(soImpl.getRootRelativePath().getPathString());
+    }
+
+    List<String> sonameLinkopts = ImmutableList.of();
+    Artifact soInterface = null;
+    if (CppHelper.useInterfaceSharedObjects(cppConfiguration, ccToolchain)
+        && emitInterfaceSharedObjects) {
+      soInterface =
+          CppHelper.getLinuxLinkedArtifact(
+              ruleContext,
+              configuration,
+              LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
+              linkedArtifactNameSuffix);
+      // TODO(b/28946988): Remove this hard-coded flag.
+      if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
+        sonameLinkopts =
+            ImmutableList.of(
+                "-Wl,-soname="
+                    + SolibSymlinkAction.getDynamicLibrarySoname(
+                        soImpl.getRootRelativePath(), /* preserveName= */ false));
+      }
+    }
+
+    CppLinkActionBuilder dynamicLinkActionBuilder =
+        newLinkActionBuilder(soImpl)
+            .setInterfaceOutput(soInterface)
+            .addObjectFiles(ccOutputs.getObjectFiles(usePicForSharedLibs))
+            .addNonCodeInputs(ccOutputs.getHeaderTokenFiles())
+            .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
+            .setLinkType(LinkTargetType.DYNAMIC_LIBRARY)
+            .setLinkStaticness(LinkStaticness.DYNAMIC)
+            .addActionInputs(linkActionInputs)
+            .setLibraryIdentifier(mainLibraryIdentifier)
+            .addLinkopts(linkopts)
+            .addLinkopts(sonameLinkopts)
+            .setRuntimeInputs(
+                ArtifactCategory.DYNAMIC_LIBRARY,
+                ccToolchain.getDynamicRuntimeLinkMiddleman(),
+                ccToolchain.getDynamicRuntimeLinkInputs())
+            .addVariablesExtensions(variablesExtensions);
+
+    if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
+      // On Windows, we cannot build a shared library with symbols unresolved, so here we
+      // dynamically
+      // link to all it's dependencies.
+      CcLinkParams.Builder ccLinkParamsBuilder =
+          CcLinkParams.builder(/* linkingStatically= */ false, /* linkShared= */ true);
+      ccLinkParamsBuilder.addCcLibrary(ruleContext);
+      dynamicLinkActionBuilder.addLinkParams(ccLinkParamsBuilder.build(), ruleContext);
+
+      // If windows_export_all_symbols feature is enabled, bazel parses object files to generate
+      // DEF file and use it to export symbols. The generated DEF file won't be used if a custom
+      // DEF file is specified by win_def_file attribute.
+      if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) {
+        Artifact generatedDefFile =
+            CppHelper.createDefFileActions(
+                ruleContext,
+                ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST),
+                ccOutputs.getObjectFiles(false),
+                SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), true));
+        dynamicLinkActionBuilder.setDefFile(generatedDefFile);
+      }
+
+      // If user specifies a custom DEF file, then we use this one instead of the generated one.
+      Artifact customDefFile = null;
+      if (ruleContext.isAttrDefined("win_def_file", LABEL)) {
+        customDefFile = ruleContext.getPrerequisiteArtifact("win_def_file", Mode.TARGET);
+      }
+      if (customDefFile != null) {
+        dynamicLinkActionBuilder.setDefFile(customDefFile);
+      }
+    }
+
+    if (!ccOutputs.getLtoBitcodeFiles().isEmpty()
+        && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
+      dynamicLinkActionBuilder.setLtoIndexing(true);
+      dynamicLinkActionBuilder.setUsePicForLtoBackendActions(usePicForSharedLibs);
+      CppLinkAction indexAction = dynamicLinkActionBuilder.build();
+      if (indexAction != null) {
+        env.registerAction(indexAction);
+      }
+
+      dynamicLinkActionBuilder.setLtoIndexing(false);
+    }
+
+    CppLinkAction dynamicLinkAction = dynamicLinkActionBuilder.build();
+    env.registerAction(dynamicLinkAction);
+
+    LibraryToLink dynamicLibrary = dynamicLinkAction.getOutputLibrary();
+    LibraryToLink interfaceLibrary = dynamicLinkAction.getInterfaceOutputLibrary();
+
+    // If shared library has neverlink=1, then leave it untouched. Otherwise,
+    // create a mangled symlink for it and from now on reference it through
+    // mangled name only.
+    //
+    // When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, we don't need to create the special
+    // solibDir, instead we use the original interface library and dynamic library.
+    if (neverlink
+        || featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
+      result.addDynamicLibrary(interfaceLibrary == null ? dynamicLibrary : interfaceLibrary);
+      result.addExecutionDynamicLibrary(dynamicLibrary);
+    } else {
+      Artifact implLibraryLinkArtifact =
+          SolibSymlinkAction.getDynamicLibrarySymlink(
+              ruleContext,
+              ccToolchain.getSolibDirectory(),
+              dynamicLibrary.getArtifact(),
+              /* preserveName= */ false,
+              /* prefixConsumer= */ false,
+              ruleContext.getConfiguration());
+      LibraryToLink implLibraryLink =
+          LinkerInputs.solibLibraryToLink(
+              implLibraryLinkArtifact, dynamicLibrary.getArtifact(), libraryIdentifier);
+      result.addExecutionDynamicLibrary(implLibraryLink);
+
+      LibraryToLink libraryLink;
+      if (interfaceLibrary == null) {
+        libraryLink = implLibraryLink;
+      } else {
+        Artifact libraryLinkArtifact =
+            SolibSymlinkAction.getDynamicLibrarySymlink(
+                ruleContext,
+                ccToolchain.getSolibDirectory(),
+                interfaceLibrary.getArtifact(),
+                /* preserveName= */ false,
+                /* prefixConsumer= */ false,
+                ruleContext.getConfiguration());
+        libraryLink =
+            LinkerInputs.solibLibraryToLink(
+                libraryLinkArtifact, interfaceLibrary.getArtifact(), libraryIdentifier);
+      }
+      result.addDynamicLibrary(libraryLink);
+    }
+  }
+
+  private CppLinkActionBuilder newLinkActionBuilder(Artifact outputArtifact) {
+    return new CppLinkActionBuilder(
+            ruleContext, outputArtifact, ccToolchain, fdoSupport, featureConfiguration, semantics)
+        .setCrosstoolInputs(ccToolchain.getLink())
+        .addNonCodeInputs(cppCompilationContext.getTransitiveCompilationPrerequisites());
+  }
+
+  /**
+   * Returns the linked artifact resulting from a linking of the given type. Consults the feature
+   * configuration to obtain an action_config that provides the artifact. If the feature
+   * configuration provides no artifact, uses a default.
+   *
+   * <p>We cannot assume that the feature configuration contains an action_config for the link
+   * action, because the linux link action depends on hardcoded values in
+   * LinkCommandLine.getRawLinkArgv(), which are applied on the condition that an action_config is
+   * not present. TODO(b/30393154): Assert that the given link action has an action_config.
+   *
+   * @throws RuleErrorException
+   */
+  private Artifact getLinkedArtifact(LinkTargetType linkTargetType) throws RuleErrorException {
+    Artifact result = null;
+    Artifact linuxDefault =
+        CppHelper.getLinuxLinkedArtifact(
+            ruleContext, configuration, linkTargetType, linkedArtifactNameSuffix);
+
+    try {
+      String maybePicName = ruleContext.getLabel().getName() + linkedArtifactNameSuffix;
+      if (linkTargetType.picness() == Picness.PIC) {
+        maybePicName =
+            CppHelper.getArtifactNameForCategory(
+                ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, maybePicName);
+      }
+      String linkedName =
+          CppHelper.getArtifactNameForCategory(
+              ruleContext, ccToolchain, linkTargetType.getLinkerOutput(), maybePicName);
+      PathFragment artifactFragment =
+          PathFragment.create(ruleContext.getLabel().getName())
+              .getParentDirectory()
+              .getRelative(linkedName);
+
+      result =
+          ruleContext.getPackageRelativeArtifact(
+              artifactFragment,
+              configuration.getBinDirectory(ruleContext.getRule().getRepository()));
+    } catch (ExpansionException e) {
+      ruleContext.throwWithRuleError(e.getMessage());
+    }
+
+    // If the linked artifact is not the linux default, then a FailAction is generated for the
+    // linux default to satisfy the requirement of the implicit output.
+    // TODO(b/30132703): Remove the implicit outputs of cc_library.
+    if (!result.equals(linuxDefault)) {
+      ruleContext.registerAction(
+          new FailAction(
+              ruleContext.getActionOwner(),
+              ImmutableList.of(linuxDefault),
+              String.format(
+                  "the given toolchain supports creation of %s instead of %s",
+                  linuxDefault.getExecPathString(), result.getExecPathString())));
+    }
+
+    return result;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
index f52a13c..885f031 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
@@ -792,7 +792,7 @@
 
     PathFragment sysroot = calculateSysroot(ruleContext, defaultSysroot);
     if (sysroot != null) {
-      variables.addStringVariable(CppModel.SYSROOT_VARIABLE_NAME, sysroot.getPathString());
+      variables.addStringVariable(CcCommon.SYSROOT_VARIABLE_NAME, sysroot.getPathString());
     }
 
     addBuildVariables(ruleContext, variables);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java
index 37960de..76d9e47 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java
@@ -153,8 +153,9 @@
    * explicit attribute, not using platform-dependent garbage bag that copts is).
    */
   public ImmutableList<String> getCopts() {
-    if (variables.isAvailable(CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME)) {
-      return Variables.toStringList(variables, CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME);
+    if (variables.isAvailable(CcCompilationHelper.USER_COMPILE_FLAGS_VARIABLE_NAME)) {
+      return Variables.toStringList(
+          variables, CcCompilationHelper.USER_COMPILE_FLAGS_VARIABLE_NAME);
     } else {
       return ImmutableList.of();
     }
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 126fda0..3d0b2c0 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
@@ -945,10 +945,11 @@
             featureConfiguration.getToolForAction(CppCompileAction.STRIP_ACTION_NAME));
     Variables variables =
         new Variables.Builder(toolchain.getBuildVariables())
-            .addStringVariable(CppModel.OUTPUT_FILE_VARIABLE_NAME, output.getExecPathString())
+            .addStringVariable(
+                CcCompilationHelper.OUTPUT_FILE_VARIABLE_NAME, output.getExecPathString())
             .addStringSequenceVariable(
-                CppModel.STRIPOPTS_VARIABLE_NAME, cppConfiguration.getStripOpts())
-            .addStringVariable(CppModel.INPUT_FILE_VARIABLE_NAME, input.getExecPathString())
+                CcCommon.STRIPOPTS_VARIABLE_NAME, cppConfiguration.getStripOpts())
+            .addStringVariable(CcCommon.INPUT_FILE_VARIABLE_NAME, input.getExecPathString())
             .build();
     ImmutableList<String> commandLine =
         ImmutableList.copyOf(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java
index dad73d3..49be968 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java
@@ -138,39 +138,42 @@
     Variables.Builder variables = new Variables.Builder(ccToolchainProvider.getBuildVariables());
     // We need to force inclusion of build_info headers
     variables.addStringSequenceVariable(
-        CppModel.INCLUDES_VARIABLE_NAME,
+        CcCommon.INCLUDES_VARIABLE_NAME,
         buildInfoHeaderArtifacts
             .stream()
             .map(Artifact::getExecPathString)
             .collect(ImmutableList.toImmutableList()));
     // Input/Output files.
-    variables.addStringVariable(CppModel.SOURCE_FILE_VARIABLE_NAME, sourceFile.getExecPathString());
-    variables.addStringVariable(CppModel.OUTPUT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
     variables.addStringVariable(
-        CppModel.OUTPUT_OBJECT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
+        CcCompilationHelper.SOURCE_FILE_VARIABLE_NAME, sourceFile.getExecPathString());
+    variables.addStringVariable(
+        CcCompilationHelper.OUTPUT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
+    variables.addStringVariable(
+        CcCompilationHelper.OUTPUT_OBJECT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
     // Include directories for (normal includes with ".", empty quote- and system- includes).
     variables.addStringSequenceVariable(
-        CppModel.INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of("."));
+        CcCompilationHelper.INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of("."));
     variables.addStringSequenceVariable(
-        CppModel.QUOTE_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
+        CcCompilationHelper.QUOTE_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
     variables.addStringSequenceVariable(
-        CppModel.SYSTEM_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
+        CcCompilationHelper.SYSTEM_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
     // Legacy flags coming from fields such as compiler_flag
     variables.addLazyStringSequenceVariable(
-        CppModel.LEGACY_COMPILE_FLAGS_VARIABLE_NAME,
-        CppModel.getLegacyCompileFlagsSupplier(
+        CcCompilationHelper.LEGACY_COMPILE_FLAGS_VARIABLE_NAME,
+        CcCompilationHelper.getLegacyCompileFlagsSupplier(
             cppConfiguration,
             ccToolchainProvider,
             sourceFile.getExecPathString(),
             ImmutableSet.of()));
     // Unfilterable flags coming from unfiltered_cxx_flag fields
     variables.addLazyStringSequenceVariable(
-        CppModel.UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME,
-        CppModel.getUnfilteredCompileFlagsSupplier(ccToolchainProvider, ImmutableSet.of()));
+        CcCompilationHelper.UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME,
+        CcCompilationHelper.getUnfilteredCompileFlagsSupplier(
+            ccToolchainProvider, ImmutableSet.of()));
     // Collect all preprocessor defines, and in each replace ${LABEL} by labelReplacements, and
     // ${OUTPUT_PATH} with outputPathReplacement.
     variables.addStringSequenceVariable(
-        CppModel.PREPROCESSOR_DEFINES_VARIABLE_NAME,
+        CcCompilationHelper.PREPROCESSOR_DEFINES_VARIABLE_NAME,
         computeAllLinkstampDefines(
             labelReplacement,
             outputReplacement,
@@ -180,7 +183,7 @@
             codeCoverageEnabled));
     // For dynamic libraries, produce position independent code.
     if (needsPic) {
-      variables.addStringVariable(CppModel.PIC_VARIABLE_NAME, "");
+      variables.addStringVariable(CcCompilationHelper.PIC_VARIABLE_NAME, "");
     }
 
     return variables.build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
deleted file mode 100644
index 34c625b..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
+++ /dev/null
@@ -1,1699 +0,0 @@
-// Copyright 2014 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.
-
-package com.google.devtools.build.lib.rules.cpp;
-
-import static com.google.devtools.build.lib.packages.BuildType.LABEL;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
-import com.google.devtools.build.lib.actions.FailAction;
-import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
-import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
-import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
-import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.packages.BuildType;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
-import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
-import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
-import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
-import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
-import com.google.devtools.build.lib.rules.cpp.Link.Picness;
-import com.google.devtools.build.lib.rules.cpp.Link.Staticness;
-import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
-import com.google.devtools.build.lib.util.FileType;
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Representation of a C/C++ compilation. Its purpose is to share the code that creates compilation
- * actions between all classes that need to do so. It follows the builder pattern - load up the
- * necessary settings and then call {@link #createCcCompileActions}.
- *
- * <p>This class is not thread-safe, and it should only be used once for each set of source files,
- * i.e. calling {@link #createCcCompileActions} will throw an Exception if called twice.
- */
-public final class CppModel {
-
-  /** Name of the build variable for the path to the source file being compiled. */
-  public static final String SOURCE_FILE_VARIABLE_NAME = "source_file";
-
-  /** Name of the build variable for the path to the input file being processed. */
-  public static final String INPUT_FILE_VARIABLE_NAME = "input_file";
-
-  /** Name of the build variable for the path to the compilation output file. */
-  public static final String OUTPUT_FILE_VARIABLE_NAME = "output_file";
-
-  /**
-   * Name of the build variable for the path to the compilation output file in case of assembly
-   * source.
-   */
-  public static final String OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME = "output_assembly_file";
-
-  /**
-   * Name of the build variable for the path to the compilation output file in case of preprocessed
-   * source.
-   */
-  public static final String OUTPUT_PREPROCESS_FILE_VARIABLE_NAME = "output_preprocess_file";
-
-  /** Name of the build variable for the path to the output file when output is an object file. */
-  public static final String OUTPUT_OBJECT_FILE_VARIABLE_NAME = "output_object_file";
-
-  /** Name of the build variable for the module file name. */
-  public static final String MODULE_NAME_VARIABLE_NAME = "module_name";
-
-  /** Name of the build variable for the module map file name. */
-  public static final String MODULE_MAP_FILE_VARIABLE_NAME = "module_map_file";
-
-  /** Name of the build variable for the dependent module map file name. */
-  public static final String DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME =
-      "dependent_module_map_files";
-
-  /** Name of the build variable for the collection of module files. */
-  public static final String MODULE_FILES_VARIABLE_NAME = "module_files";
-
-  /**
-   * Name of the build variable for includes that compiler needs to include into sources to be
-   * compiled.
-   */
-  public static final String INCLUDES_VARIABLE_NAME = "includes";
-
-  /**
-   * Name of the build variable for the collection of include paths.
-   *
-   * @see CppCompilationContext#getIncludeDirs().
-   */
-  public static final String INCLUDE_PATHS_VARIABLE_NAME = "include_paths";
-
-  /**
-   * Name of the build variable for the collection of quote include paths.
-   *
-   * @see CppCompilationContext#getIncludeDirs().
-   */
-  public static final String QUOTE_INCLUDE_PATHS_VARIABLE_NAME = "quote_include_paths";
-
-  /**
-   * Name of the build variable for the collection of system include paths.
-   *
-   * @see CppCompilationContext#getIncludeDirs().
-   */
-  public static final String SYSTEM_INCLUDE_PATHS_VARIABLE_NAME = "system_include_paths";
-
-  /** Name of the build variable for the dependency file path */
-  public static final String DEPENDENCY_FILE_VARIABLE_NAME = "dependency_file";
-
-  /** Name of the build variable for the collection of macros defined for preprocessor. */
-  public static final String PREPROCESSOR_DEFINES_VARIABLE_NAME = "preprocessor_defines";
-
-  /** Name of the build variable present when the output is compiled as position independent. */
-  public static final String PIC_VARIABLE_NAME = "pic";
-
-  /** Name of the build variable for the gcov coverage file path. */
-  public static final String GCOV_GCNO_FILE_VARIABLE_NAME = "gcov_gcno_file";
-
-  /** Name of the build variable for the per object debug info file. */
-  public static final String PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME =
-      "per_object_debug_info_file";
-
-  /** Name of the build variable for the LTO indexing bitcode file. */
-  public static final String LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME = "lto_indexing_bitcode_file";
-
-  /** Name of the build variable for stripopts for the strip action. */
-  public static final String STRIPOPTS_VARIABLE_NAME = "stripopts";
-
-  /**
-   * Build variable for all flags coming from legacy crosstool fields, such as compiler_flag,
-   * optional_compiler_flag, cxx_flag, optional_cxx_flag.
-   */
-  public static final String LEGACY_COMPILE_FLAGS_VARIABLE_NAME = "legacy_compile_flags";
-
-  /**
-   * Build variable for all flags coming from copt rule attribute, and from --copt, --cxxopt, or
-   * --conlyopt options.
-   */
-  public static final String USER_COMPILE_FLAGS_VARIABLE_NAME = "user_compile_flags";
-
-  /** Build variable for flags coming from unfiltered_cxx_flag CROSSTOOL fields. */
-  public static final String UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME = "unfiltered_compile_flags";
-
-  /** Name of the build variable for the sysroot path variable name. */
-  public static final String SYSROOT_VARIABLE_NAME = "sysroot";
-
-  private static final String PIC_CONFIGURATION_ERROR =
-      "PIC compilation is requested but the toolchain does not support it";
-
-  private final CppSemantics semantics;
-  private final RuleContext ruleContext;
-  private final BuildConfiguration configuration;
-  private final CppConfiguration cppConfiguration;
-
-  // compile model
-  private CppCompilationContext context;
-  private final Set<CppSource> sourceFiles = new LinkedHashSet<>();
-  private final List<Artifact> compilationMandatoryInputs = new ArrayList<>();
-  private final List<Artifact> additionalIncludeScanningRoots = new ArrayList<>();
-  private final ImmutableList<String> copts;
-  private final CoptsFilter coptsFilter;
-  private boolean fake;
-  private boolean maySaveTemps;
-  private CcCompilationOutputs compilationOutputs;
-
-  // link model
-  private final List<String> linkopts = new ArrayList<>();
-  private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY;
-  private boolean neverLink;
-  private final List<Artifact> linkActionInputs = new ArrayList<>();
-  private boolean allowInterfaceSharedObjects;
-  private boolean createDynamicLibrary = true;
-  private boolean createStaticLibraries = true;
-  private Artifact soImplArtifact;
-  private FeatureConfiguration featureConfiguration;
-  private List<VariablesExtension> variablesExtensions = new ArrayList<>();
-  private final CcToolchainProvider ccToolchain;
-  private final FdoSupportProvider fdoSupport;
-  private String linkedArtifactNameSuffix = "";
-  private final ImmutableSet<String> features;
-  private boolean generateNoPic = true;
-
-  public CppModel(
-      RuleContext ruleContext,
-      CppSemantics semantics,
-      CcToolchainProvider ccToolchain,
-      FdoSupportProvider fdoSupport,
-      ImmutableList<String> copts) {
-    this(
-        ruleContext,
-        semantics,
-        ccToolchain,
-        fdoSupport,
-        ruleContext.getConfiguration(),
-        copts,
-        CoptsFilter.alwaysPasses());
-  }
-
-  public CppModel(
-      RuleContext ruleContext,
-      CppSemantics semantics,
-      CcToolchainProvider ccToolchain,
-      FdoSupportProvider fdoSupport,
-      ImmutableList<String> copts,
-      CoptsFilter coptsFilter) {
-    this(
-        ruleContext,
-        semantics,
-        ccToolchain,
-        fdoSupport,
-        ruleContext.getConfiguration(),
-        copts,
-        coptsFilter);
- }
-
-  public CppModel(
-      RuleContext ruleContext,
-      CppSemantics semantics,
-      CcToolchainProvider ccToolchain,
-      FdoSupportProvider fdoSupport,
-      BuildConfiguration configuration,
-      ImmutableList<String> copts,
-      CoptsFilter coptsFilter) {
-    this.ruleContext = Preconditions.checkNotNull(ruleContext);
-    this.semantics = semantics;
-    this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
-    this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
-    this.configuration = configuration;
-    this.copts = copts;
-    this.coptsFilter = Preconditions.checkNotNull(coptsFilter);
-    cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
-    features = ruleContext.getFeatures();
-  }
-
-  private Artifact getDwoFile(Artifact outputFile) {
-    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ".dwo");
-  }
-
-  private Artifact getLtoIndexingFile(Artifact outputFile) {
-    String ext = Iterables.getOnlyElement(CppFileTypes.LTO_INDEXING_OBJECT_FILE.getExtensions());
-    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ext);
-  }
-
-  /**
-   * If the cpp compilation is a fake, then it creates only a single compile action without PIC.
-   * Defaults to false.
-   */
-  public CppModel setFake(boolean fake) {
-    this.fake = fake;
-    return this;
-  }
-
-  /**
-   * Whether to create actions for temps. This defaults to false.
-   */
-  public CppModel setSaveTemps(boolean maySaveTemps) {
-    this.maySaveTemps = maySaveTemps;
-    return this;
-  }
-
-  /**
-   * Sets the compilation context, i.e. include directories and allowed header files inclusions.
-   */
-  public CppModel setContext(CppCompilationContext context) {
-    this.context = context;
-    return this;
-  }
-
-  /**
-   * Adds a single source file to be compiled. Note that this should only be called for primary
-   * compilation units, including module files or headers to be parsed or preprocessed.
-   */
-  public CppModel addCompilationUnitSources(
-      Iterable<Artifact> sourceFiles, Label sourceLabel, CppSource.Type type) {
-    for (Artifact sourceFile : sourceFiles) {
-      this.sourceFiles.add(CppSource.create(sourceFile, sourceLabel, type));
-    }
-    return this;
-  }
-
-  /**
-   * Adds all the source files. Note that this should only be called for primary compilation units,
-   * including module files or headers to be parsed or preprocessed.
-   */
-  public CppModel addCompilationUnitSources(Set<CppSource> sources) {
-    this.sourceFiles.addAll(sources);
-    return this;
-  }
-
-  /** Adds compilation mandatory inputs. */
-  public CppModel addCompilationMandatoryInputs(Collection<Artifact> compilationMandatoryInputs) {
-    this.compilationMandatoryInputs.addAll(compilationMandatoryInputs);
-    return this;
-  }
-
-  /** Adds additional includes to be scanned. */
-  public CppModel addAdditionalIncludeScanningRoots(
-      Collection<Artifact> additionalIncludeScanningRoots) {
-    this.additionalIncludeScanningRoots.addAll(additionalIncludeScanningRoots);
-    return this;
-  }
-
-  /**
-   * Adds the given linkopts to the optional dynamic library link command.
-   */
-  public CppModel addLinkopts(Collection<String> linkopts) {
-    this.linkopts.addAll(linkopts);
-    return this;
-  }
-
-  /**
-   * Adds the given variablesExensions for templating the crosstool.
-   *
-   * <p>In general, we prefer the build variables (especially those that derive strictly from
-   * the configuration) be learned by inspecting the CcToolchain, as passed to the rule in the
-   * CcToolchainProvider.  However, for build variables that must be injected into the rule
-   * implementation (ex. build variables learned from the BUILD file), should be added using the
-   * VariablesExtension abstraction.  This allows the injection to construct non-trivial build
-   * variables (lists, ect.).
-   */
-  public CppModel addVariablesExtension(Collection<VariablesExtension> variablesExtensions) {
-    this.variablesExtensions.addAll(variablesExtensions);
-    return this;
-  }
-
-  /**
-   * Sets the link type used for the link actions. Note that only static links are supported at this
-   * time.
-   */
-  public CppModel setLinkTargetType(LinkTargetType linkType) {
-    this.linkType = linkType;
-    return this;
-  }
-
-  public CppModel setNeverLink(boolean neverLink) {
-    this.neverLink = neverLink;
-    return this;
-  }
-
-  /**
-   * Adds an artifact to the inputs of any link actions created by this CppModel.
-   */
-  public CppModel addLinkActionInputs(Collection<Artifact> inputs) {
-    this.linkActionInputs.addAll(inputs);
-    return this;
-  }
-
-  /**
-   * Whether to allow interface dynamic libraries. Note that setting this to true only has an effect
-   * if the configuration allows it. Defaults to false.
-   */
-  public CppModel setAllowInterfaceSharedObjects(boolean allowInterfaceSharedObjects) {
-    // TODO(bazel-team): Set the default to true, and require explicit action to disable it.
-    this.allowInterfaceSharedObjects = allowInterfaceSharedObjects;
-    return this;
-  }
-
-  public CppModel setCreateDynamicLibrary(boolean createDynamicLibrary) {
-    this.createDynamicLibrary = createDynamicLibrary;
-    return this;
-  }
-
-  public CppModel setCreateStaticLibraries(boolean createStaticLibraries) {
-    this.createStaticLibraries = createStaticLibraries;
-    return this;
-  }
-
-  public CppModel setDynamicLibrary(Artifact soImplFilename) {
-    this.soImplArtifact = soImplFilename;
-    return this;
-  }
-
-  /** Sets the feature configuration to be used for C/C++ actions. */
-  public CppModel setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
-    this.featureConfiguration = featureConfiguration;
-    return this;
-  }
-
-  /*
-   * Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule
-   * labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may
-   * generate the same linked artifact and therefore lead to artifact conflicts. This method
-   * provides a way to avoid this artifact conflict by allowing different callers acting on the same
-   * rule to provide a suffix that will be used to scope their own linked artifacts.
-   */
-  public CppModel setLinkedArtifactNameSuffix(String suffix) {
-    this.linkedArtifactNameSuffix = suffix;
-    return this;
-  }
-
-  /** no-PIC actions won't be generated. */
-  public CppModel setGenerateNoPic(boolean generateNoPic) {
-    this.generateNoPic = generateNoPic;
-    return this;
-  }
-
-  /**
-   * @returns whether we want to provide header modules for the current target.
-   */
-  private boolean shouldProvideHeaderModules() {
-    return featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES)
-        && !cppConfiguration.isLipoContextCollector();
-  }
-
-  /**
-   * @return the non-pic header module artifact for the current target.
-   */
-  public Artifact getHeaderModule(Artifact moduleMapArtifact) {
-    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
-    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
-    return ruleContext.getRelatedArtifact(outputName, ".pcm");
-  }
-
-  /**
-   * @return the pic header module artifact for the current target.
-   */
-  public Artifact getPicHeaderModule(Artifact moduleMapArtifact) {
-    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
-    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
-    return ruleContext.getRelatedArtifact(outputName, ".pic.pcm");
-  }
-
-  /** @return whether this target needs to generate pic actions. */
-  private boolean getGeneratePicActions() {
-    return featureConfiguration.isEnabled(CppRuleClasses.PIC)
-        && CppHelper.usePic(ruleContext, ccToolchain, false);
-  }
-
-  /** @return whether this target needs to generate non-pic actions. */
-  private boolean getGenerateNoPicActions() {
-    if (!generateNoPic) {
-      return false;
-    }
-    boolean picFeatureEnabled = featureConfiguration.isEnabled(CppRuleClasses.PIC);
-    boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, true);
-    boolean usePicForNonBinaries = CppHelper.usePic(ruleContext, ccToolchain, false);
-
-    if (!usePicForNonBinaries) {
-      // This means you have to be prepared to use non-pic output for dynamic libraries.
-      return true;
-    }
-
-    // Either you're only making a dynamic library (onlySingleOutput) or pic should be used
-    // in all cases.
-    if (usePicForBinaries) {
-      if (picFeatureEnabled) {
-        return false;
-      }
-      ruleContext.ruleError(PIC_CONFIGURATION_ERROR);
-    }
-
-    return true;
-  }
-
-  /**
-   * @return whether this target needs to generate a pic header module.
-   */
-  public boolean getGeneratesPicHeaderModule() {
-    return shouldProvideHeaderModules() && !fake && getGeneratePicActions();
-  }
-
-  /**
-   * @return whether this target needs to generate a non-pic header module.
-   */
-  public boolean getGeneratesNoPicHeaderModule() {
-    return shouldProvideHeaderModules() && !fake && getGenerateNoPicActions();
-  }
-
-  /**
-   * Returns a {@code CppCompileActionBuilder} with the common fields for a C++ compile action being
-   * initialized.
-   */
-  private CppCompileActionBuilder initializeCompileAction(Artifact sourceArtifact) {
-    CppCompileActionBuilder builder = createCompileActionBuilder(sourceArtifact);
-    builder.setFeatureConfiguration(featureConfiguration);
-
-    return builder;
-  }
-
-  /** Get the safe path strings for a list of paths to use in the build variables. */
-  private ImmutableSet<String> getSafePathStrings(Collection<PathFragment> paths) {
-    ImmutableSet.Builder<String> result = ImmutableSet.builder();
-    for (PathFragment path : paths) {
-      result.add(path.getSafePathString());
-    }
-    return result.build();
-  }
-
-  /**
-   * Supplier that computes unfiltered_compile_flags lazily at the execution phase.
-   *
-   * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables
-   * only to arguments (to prevent accidental capture of enclosing instance which could regress
-   * memory).
-   */
-  public static Supplier<ImmutableList<String>> getUnfilteredCompileFlagsSupplier(
-      CcToolchainProvider ccToolchain, ImmutableSet<String> features) {
-    return () -> ccToolchain.getUnfilteredCompilerOptions(features);
-  }
-
-  /**
-   * Supplier that computes legacy_compile_flags lazily at the execution phase.
-   *
-   * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only
-   * to arguments (to prevent accidental capture of enclosing instance which could regress memory).
-   */
-  public static Supplier<ImmutableList<String>> getLegacyCompileFlagsSupplier(
-      CppConfiguration cppConfiguration,
-      CcToolchainProvider toolchain,
-      String sourceFilename,
-      ImmutableSet<String> features) {
-    return () -> {
-      ImmutableList.Builder<String> legacyCompileFlags = ImmutableList.builder();
-      legacyCompileFlags.addAll(
-          CppHelper.getCompilerOptions(cppConfiguration, toolchain, features));
-      if (CppFileTypes.C_SOURCE.matches(sourceFilename)) {
-        legacyCompileFlags.addAll(cppConfiguration.getCOptions());
-      }
-      if (CppFileTypes.CPP_SOURCE.matches(sourceFilename)
-          || CppFileTypes.CPP_HEADER.matches(sourceFilename)
-          || CppFileTypes.CPP_MODULE_MAP.matches(sourceFilename)
-          || CppFileTypes.CLIF_INPUT_PROTO.matches(sourceFilename)) {
-        legacyCompileFlags.addAll(CppHelper.getCxxOptions(cppConfiguration, toolchain, features));
-      }
-      return legacyCompileFlags.build();
-    };
-  }
-
-  private void setupCompileBuildVariables(
-      CppCompileActionBuilder builder,
-      Label sourceLabel,
-      boolean usePic,
-      PathFragment ccRelativeName,
-      PathFragment autoFdoImportPath,
-      Artifact gcnoFile,
-      Artifact dwoFile,
-      Artifact ltoIndexingFile,
-      CppModuleMap cppModuleMap) {
-    CcToolchainFeatures.Variables.Builder buildVariables =
-        new CcToolchainFeatures.Variables.Builder(ccToolchain.getBuildVariables());
-
-    CppCompilationContext builderContext = builder.getContext();
-    Artifact sourceFile = builder.getSourceFile();
-    Artifact outputFile = builder.getOutputFile();
-    String realOutputFilePath;
-
-    buildVariables.addStringVariable(SOURCE_FILE_VARIABLE_NAME, sourceFile.getExecPathString());
-    buildVariables.addStringVariable(OUTPUT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
-    buildVariables.addStringSequenceVariable(
-        USER_COMPILE_FLAGS_VARIABLE_NAME,
-        ImmutableList.<String>builder()
-            .addAll(copts)
-            .addAll(collectPerFileCopts(sourceFile, sourceLabel))
-            .build());
-
-    String sourceFilename = sourceFile.getExecPathString();
-    buildVariables.addLazyStringSequenceVariable(
-        LEGACY_COMPILE_FLAGS_VARIABLE_NAME,
-        getLegacyCompileFlagsSupplier(cppConfiguration, ccToolchain, sourceFilename, features));
-
-    if (!CppFileTypes.OBJC_SOURCE.matches(sourceFilename)
-        && !CppFileTypes.OBJCPP_SOURCE.matches(sourceFilename)) {
-      buildVariables.addLazyStringSequenceVariable(
-          UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME,
-          getUnfilteredCompileFlagsSupplier(ccToolchain, features));
-    }
-
-    if (builder.getTempOutputFile() != null) {
-      realOutputFilePath = builder.getTempOutputFile().getPathString();
-    } else {
-      realOutputFilePath = builder.getOutputFile().getExecPathString();
-    }
-
-    if (FileType.contains(outputFile, CppFileTypes.ASSEMBLER, CppFileTypes.PIC_ASSEMBLER)) {
-      buildVariables.addStringVariable(OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME, realOutputFilePath);
-    } else if (FileType.contains(outputFile, CppFileTypes.PREPROCESSED_C,
-        CppFileTypes.PREPROCESSED_CPP, CppFileTypes.PIC_PREPROCESSED_C,
-        CppFileTypes.PIC_PREPROCESSED_CPP)) {
-      buildVariables.addStringVariable(OUTPUT_PREPROCESS_FILE_VARIABLE_NAME, realOutputFilePath);
-    } else {
-      buildVariables.addStringVariable(OUTPUT_OBJECT_FILE_VARIABLE_NAME, realOutputFilePath);
-    }
-
-    DotdFile dotdFile =
-        isGenerateDotdFile(sourceFile) ? Preconditions.checkNotNull(builder.getDotdFile()) : null;
-    // Set dependency_file to enable <object>.d file generation.
-    if (dotdFile != null) {
-      buildVariables.addStringVariable(
-          DEPENDENCY_FILE_VARIABLE_NAME, dotdFile.getSafeExecPath().getPathString());
-    }
-
-    if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS) && cppModuleMap != null) {
-      // If the feature is enabled and cppModuleMap is null, we are about to fail during analysis
-      // in any case, but don't crash.
-      buildVariables.addStringVariable(MODULE_NAME_VARIABLE_NAME, cppModuleMap.getName());
-      buildVariables.addStringVariable(
-          MODULE_MAP_FILE_VARIABLE_NAME, cppModuleMap.getArtifact().getExecPathString());
-      StringSequenceBuilder sequence = new StringSequenceBuilder();
-      for (Artifact artifact : builderContext.getDirectModuleMaps()) {
-        sequence.addValue(artifact.getExecPathString());
-      }
-      buildVariables.addCustomBuiltVariable(DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME, sequence);
-    }
-    if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES)) {
-      // Module inputs will be set later when the action is executed.
-      buildVariables.addStringSequenceVariable(MODULE_FILES_VARIABLE_NAME, ImmutableSet.of());
-    }
-    if (featureConfiguration.isEnabled(CppRuleClasses.INCLUDE_PATHS)) {
-      buildVariables.addStringSequenceVariable(
-          INCLUDE_PATHS_VARIABLE_NAME, getSafePathStrings(builderContext.getIncludeDirs()));
-      buildVariables.addStringSequenceVariable(
-          QUOTE_INCLUDE_PATHS_VARIABLE_NAME,
-          getSafePathStrings(builderContext.getQuoteIncludeDirs()));
-      buildVariables.addStringSequenceVariable(
-          SYSTEM_INCLUDE_PATHS_VARIABLE_NAME,
-          getSafePathStrings(builderContext.getSystemIncludeDirs()));
-    }
-
-    if (featureConfiguration.isEnabled(CppRuleClasses.PREPROCESSOR_DEFINES)) {
-      String fdoBuildStamp = CppHelper.getFdoBuildStamp(ruleContext, fdoSupport.getFdoSupport());
-      ImmutableList<String> defines;
-      if (fdoBuildStamp != null) {
-        // Stamp FDO builds with FDO subtype string
-        defines = ImmutableList.<String>builder()
-            .addAll(builderContext.getDefines())
-            .add(CppConfiguration.FDO_STAMP_MACRO
-                + "=\"" + CppHelper.getFdoBuildStamp(
-                    ruleContext, fdoSupport.getFdoSupport()) + "\"")
-            .build();
-      } else {
-        defines = builderContext.getDefines();
-      }
-
-      buildVariables.addStringSequenceVariable(PREPROCESSOR_DEFINES_VARIABLE_NAME, defines);
-    }
-
-    if (usePic) {
-      if (!featureConfiguration.isEnabled(CppRuleClasses.PIC)) {
-        ruleContext.ruleError(PIC_CONFIGURATION_ERROR);
-      }
-      buildVariables.addStringVariable(PIC_VARIABLE_NAME, "");
-    }
-
-    if (ccRelativeName != null) {
-      fdoSupport.getFdoSupport().configureCompilation(
-          builder, buildVariables, ruleContext, ccRelativeName, autoFdoImportPath, usePic,
-          featureConfiguration, fdoSupport);
-    }
-    if (gcnoFile != null) {
-      buildVariables.addStringVariable(GCOV_GCNO_FILE_VARIABLE_NAME, gcnoFile.getExecPathString());
-    }
-
-    if (dwoFile != null) {
-      buildVariables.addStringVariable(
-          PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME, dwoFile.getExecPathString());
-    }
-
-    if (ltoIndexingFile != null) {
-      buildVariables.addStringVariable(
-          LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME, ltoIndexingFile.getExecPathString());
-    }
-
-    for (VariablesExtension extension : variablesExtensions) {
-      extension.addVariables(buildVariables);
-    }
-
-    CcToolchainFeatures.Variables variables = buildVariables.build();
-    builder.setVariables(variables);
-  }
-
-  private ImmutableList<String> collectPerFileCopts(Artifact sourceFile, Label sourceLabel) {
-    return cppConfiguration
-        .getPerFileCopts()
-        .stream()
-        .filter(
-            perLabelOptions ->
-                (sourceLabel != null && perLabelOptions.isIncluded(sourceLabel))
-                    || perLabelOptions.isIncluded(sourceFile))
-        .map(PerLabelOptions::getOptions)
-        .flatMap(options -> options.stream())
-        .collect(ImmutableList.toImmutableList());
-  }
-
-  /** Returns true if Dotd file should be generated. */
-  private boolean isGenerateDotdFile(Artifact sourceArtifact) {
-    return CppFileTypes.headerDiscoveryRequired(sourceArtifact)
-        && !featureConfiguration.isEnabled(CppRuleClasses.PARSE_SHOWINCLUDES);
-  }
-
-  /**
-   * Constructs the C++ compiler actions. It generally creates one action for every specified source
-   * file. It takes into account LIPO, fake-ness, coverage, and PIC, in addition to using the
-   * settings specified on the current object. This method should only be called once.
-   */
-  public CcCompilationOutputs createCcCompileActions() throws RuleErrorException {
-    CcCompilationOutputs.Builder result = new CcCompilationOutputs.Builder();
-    Preconditions.checkNotNull(context);
-    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
-
-    if (shouldProvideHeaderModules()) {
-      Label moduleMapLabel = Label.parseAbsoluteUnchecked(context.getCppModuleMap().getName());
-      Collection<Artifact> modules = createModuleAction(result, context.getCppModuleMap());
-      if (featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN)) {
-        for (Artifact module : modules) {
-          // TODO(djasper): Investigate whether we need to use a label separate from that of the
-          // module map. It is used for per-file-copts.
-          createModuleCodegenAction(result, moduleMapLabel, module);
-        }
-      }
-    } else if (context.getVerificationModuleMap() != null) {
-      Collection<Artifact> modules = createModuleAction(result, context.getVerificationModuleMap());
-      for (Artifact module : modules) {
-        result.addHeaderTokenFile(module);
-      }
-    }
-
-    for (CppSource source : sourceFiles) {
-      Artifact sourceArtifact = source.getSource();
-      Label sourceLabel = source.getLabel();
-      String outputName =
-          FileSystemUtils.removeExtension(sourceArtifact.getRootRelativePath()).getPathString();
-      CppCompileActionBuilder builder = initializeCompileAction(sourceArtifact);
-
-      builder.setSemantics(semantics)
-          .addMandatoryInputs(compilationMandatoryInputs)
-          .addAdditionalIncludeScanningRoots(additionalIncludeScanningRoots);
-
-      boolean bitcodeOutput =
-          featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
-              && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename());
-
-      if (!sourceArtifact.isTreeArtifact()) {
-        switch (source.getType()) {
-          case HEADER:
-            createHeaderAction(
-                sourceLabel, outputName, result, env, builder, isGenerateDotdFile(sourceArtifact));
-            break;
-          default:
-            createSourceAction(
-                sourceLabel,
-                outputName,
-                result,
-                env,
-                sourceArtifact,
-                builder,
-                // TODO(plf): Continue removing CLIF logic from C++. Follow up changes would include
-                // refactoring CppSource.Type and ArtifactCategory to be classes instead of enums
-                // that could be instantiated with arbitrary values.
-                source.getType() == CppSource.Type.CLIF_INPUT_PROTO
-                    ? ArtifactCategory.CLIF_OUTPUT_PROTO
-                    : ArtifactCategory.OBJECT_FILE,
-                context.getCppModuleMap(),
-                /* addObject= */ true,
-                isCodeCoverageEnabled(),
-                // The source action does not generate dwo when it has bitcode
-                // output (since it isn't generating a native object with debug
-                // info). In that case the LtoBackendAction will generate the dwo.
-                CppHelper.shouldCreatePerObjectDebugInfo(
-                        cppConfiguration, ccToolchain, featureConfiguration)
-                    && !bitcodeOutput,
-                isGenerateDotdFile(sourceArtifact));
-            break;
-        }
-      } else {
-        switch (source.getType()) {
-          case HEADER:
-            Artifact headerTokenFile =
-                createCompileActionTemplate(
-                    env,
-                    source,
-                    builder,
-                    ImmutableList.of(
-                        ArtifactCategory.GENERATED_HEADER, ArtifactCategory.PROCESSED_HEADER),
-                    false);
-            result.addHeaderTokenFile(headerTokenFile);
-            break;
-          case SOURCE:
-            Artifact objectFile =
-                createCompileActionTemplate(
-                    env, source, builder, ImmutableList.of(ArtifactCategory.OBJECT_FILE), false);
-            result.addObjectFile(objectFile);
-
-            if (getGeneratePicActions()) {
-              Artifact picObjectFile =
-                  createCompileActionTemplate(
-                      env,
-                      source,
-                      builder,
-                      ImmutableList.of(ArtifactCategory.PIC_OBJECT_FILE),
-                      true);
-              result.addPicObjectFile(picObjectFile);
-            }
-            break;
-          default:
-            throw new IllegalStateException(
-                "Encountered invalid source types when creating CppCompileActionTemplates");
-        }
-      }
-    }
-
-    compilationOutputs = result.build();
-    return compilationOutputs;
-  }
-
-  private void createHeaderAction(
-      Label sourceLabel,
-      String outputName,
-      CcCompilationOutputs.Builder result,
-      AnalysisEnvironment env,
-      CppCompileActionBuilder builder,
-      boolean generateDotd)
-      throws RuleErrorException {
-    String outputNameBase = CppHelper.getArtifactNameForCategory(
-        ruleContext, ccToolchain, ArtifactCategory.GENERATED_HEADER, outputName);
-
-    builder
-        .setOutputs(ruleContext, ArtifactCategory.PROCESSED_HEADER, outputNameBase, generateDotd)
-        // If we generate pic actions, we prefer the header actions to use the pic artifacts.
-        .setPicMode(getGeneratePicActions());
-    setupCompileBuildVariables(
-        builder,
-        sourceLabel,
-        this.getGeneratePicActions(),
-        /* ccRelativeName= */ null,
-        /* autoFdoImportPath= */ null,
-        /* gcnoFile= */ null,
-        /* dwoFile= */ null,
-        /* ltoIndexingFile= */ null,
-        builder.getContext().getCppModuleMap());
-    semantics.finalizeCompileActionBuilder(ruleContext, builder);
-    CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
-    env.registerAction(compileAction);
-    Artifact tokenFile = compileAction.getOutputFile();
-    result.addHeaderTokenFile(tokenFile);
-  }
-
-  private void createModuleCodegenAction(
-      CcCompilationOutputs.Builder result, Label sourceLabel, Artifact module)
-      throws RuleErrorException {
-    if (fake) {
-      // We can't currently foresee a situation where we'd want nocompile tests for module codegen.
-      // If we find one, support needs to be added here.
-      return;
-    }
-    String outputName = module.getRootRelativePath().getPathString();
-
-    // TODO(djasper): Make this less hacky after refactoring how the PIC/noPIC actions are created.
-    boolean pic = module.getFilename().contains(".pic.");
-
-    CppCompileActionBuilder builder = initializeCompileAction(module);
-    builder.setSemantics(semantics);
-    builder.setPicMode(pic);
-    builder.setOutputs(
-        ruleContext, ArtifactCategory.OBJECT_FILE, outputName, isGenerateDotdFile(module));
-    PathFragment ccRelativeName = module.getRootRelativePath();
-
-    String gcnoFileName =
-        CppHelper.getArtifactNameForCategory(
-            ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName);
-    // TODO(djasper): This is now duplicated. Refactor the various create..Action functions.
-    Artifact gcnoFile =
-        isCodeCoverageEnabled() && !CppHelper.isLipoOptimization(cppConfiguration, ccToolchain)
-            ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
-            : null;
-
-    boolean generateDwo =
-        CppHelper.shouldCreatePerObjectDebugInfo(
-            cppConfiguration, ccToolchain, featureConfiguration);
-    Artifact dwoFile = generateDwo ? getDwoFile(builder.getOutputFile()) : null;
-    // TODO(tejohnson): Add support for ThinLTO if needed.
-    boolean bitcodeOutput =
-        featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
-            && CppFileTypes.LTO_SOURCE.matches(module.getFilename());
-    Preconditions.checkState(!bitcodeOutput);
-
-    setupCompileBuildVariables(
-        builder,
-        sourceLabel,
-        /* usePic= */ pic,
-        ccRelativeName,
-        module.getExecPath(),
-        gcnoFile,
-        dwoFile,
-        /* ltoIndexingFile= */ null,
-        builder.getContext().getCppModuleMap());
-
-    builder.setGcnoFile(gcnoFile);
-    builder.setDwoFile(dwoFile);
-
-    semantics.finalizeCompileActionBuilder(ruleContext, builder);
-    CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
-    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
-    env.registerAction(compileAction);
-    Artifact objectFile = compileAction.getOutputFile();
-    if (pic) {
-      result.addPicObjectFile(objectFile);
-    } else {
-      result.addObjectFile(objectFile);
-    }
-  }
-
-  private Collection<Artifact> createModuleAction(
-      CcCompilationOutputs.Builder result, CppModuleMap cppModuleMap) throws RuleErrorException {
-    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
-    Artifact moduleMapArtifact = cppModuleMap.getArtifact();
-    CppCompileActionBuilder builder = initializeCompileAction(moduleMapArtifact);
-
-    builder.setSemantics(semantics);
-
-    // A header module compile action is just like a normal compile action, but:
-    // - the compiled source file is the module map
-    // - it creates a header module (.pcm file).
-    return createSourceAction(
-        Label.parseAbsoluteUnchecked(cppModuleMap.getName()),
-        FileSystemUtils.removeExtension(moduleMapArtifact.getRootRelativePath()).getPathString(),
-        result,
-        env,
-        moduleMapArtifact,
-        builder,
-        ArtifactCategory.CPP_MODULE,
-        cppModuleMap,
-        /* addObject= */ false,
-        /* enableCoverage= */ false,
-        /* generateDwo= */ false,
-        isGenerateDotdFile(moduleMapArtifact));
-  }
-
-  private Collection<Artifact> createSourceAction(
-      Label sourceLabel,
-      String outputName,
-      CcCompilationOutputs.Builder result,
-      AnalysisEnvironment env,
-      Artifact sourceArtifact,
-      CppCompileActionBuilder builder,
-      ArtifactCategory outputCategory,
-      CppModuleMap cppModuleMap,
-      boolean addObject,
-      boolean enableCoverage,
-      boolean generateDwo,
-      boolean generateDotd)
-      throws RuleErrorException {
-    ImmutableList.Builder<Artifact> directOutputs = new ImmutableList.Builder<>();
-    PathFragment ccRelativeName = sourceArtifact.getRootRelativePath();
-    if (CppHelper.isLipoOptimization(cppConfiguration, ccToolchain)) {
-      // TODO(bazel-team): we shouldn't be needing this, merging context with the binary
-      // is a superset of necessary information.
-      LipoContextProvider lipoProvider =
-          Preconditions.checkNotNull(CppHelper.getLipoContextProvider(ruleContext), outputName);
-      builder.setContext(CppCompilationContext.mergeForLipo(lipoProvider.getLipoContext(),
-          context));
-    }
-    boolean generatePicAction = getGeneratePicActions();
-    boolean generateNoPicAction = getGenerateNoPicActions();
-    Preconditions.checkState(generatePicAction || generateNoPicAction);
-    if (fake) {
-      boolean usePic = !generateNoPicAction;
-      createFakeSourceAction(
-          sourceLabel,
-          outputName,
-          result,
-          env,
-          builder,
-          outputCategory,
-          addObject,
-          ccRelativeName,
-          sourceArtifact.getExecPath(),
-          usePic,
-          generateDotd);
-    } else {
-      boolean bitcodeOutput =
-          featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
-              && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename());
-
-      // Create PIC compile actions (same as non-PIC, but use -fPIC and
-      // generate .pic.o, .pic.d, .pic.gcno instead of .o, .d, .gcno.)
-      if (generatePicAction) {
-        String picOutputBase = CppHelper.getArtifactNameForCategory(ruleContext,
-            ccToolchain, ArtifactCategory.PIC_FILE, outputName);
-        CppCompileActionBuilder picBuilder = copyAsPicBuilder(
-            builder, picOutputBase, outputCategory, generateDotd);
-        String gcnoFileName = CppHelper.getArtifactNameForCategory(ruleContext,
-            ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, picOutputBase);
-        Artifact gcnoFile = enableCoverage
-            ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
-            : null;
-        Artifact dwoFile = generateDwo ? getDwoFile(picBuilder.getOutputFile()) : null;
-        Artifact ltoIndexingFile =
-            bitcodeOutput ? getLtoIndexingFile(picBuilder.getOutputFile()) : null;
-
-        setupCompileBuildVariables(
-            picBuilder,
-            sourceLabel,
-            /* usePic= */ true,
-            ccRelativeName,
-            sourceArtifact.getExecPath(),
-            gcnoFile,
-            dwoFile,
-            ltoIndexingFile,
-            cppModuleMap);
-
-        if (maySaveTemps) {
-          result.addTemps(
-              createTempsActions(
-                  sourceArtifact,
-                  sourceLabel,
-                  outputName,
-                  picBuilder,
-                  /* usePic= */ true,
-                  /* generateDotd= */ generateDotd,
-                  ccRelativeName));
-        }
-
-        picBuilder.setGcnoFile(gcnoFile);
-        picBuilder.setDwoFile(dwoFile);
-        picBuilder.setLtoIndexingFile(ltoIndexingFile);
-
-        semantics.finalizeCompileActionBuilder(ruleContext, picBuilder);
-        CppCompileAction picAction = picBuilder.buildOrThrowRuleError(ruleContext);
-        env.registerAction(picAction);
-        directOutputs.add(picAction.getOutputFile());
-        if (addObject) {
-          result.addPicObjectFile(picAction.getOutputFile());
-
-          if (bitcodeOutput) {
-            result.addLtoBitcodeFile(picAction.getOutputFile(), ltoIndexingFile);
-          }
-        }
-        if (dwoFile != null) {
-          // Host targets don't produce .dwo files.
-          result.addPicDwoFile(dwoFile);
-        }
-        if (cppConfiguration.isLipoContextCollector() && !generateNoPicAction) {
-          result.addLipoScannable(picAction);
-        }
-      }
-
-      if (generateNoPicAction) {
-        Artifact noPicOutputFile = CppHelper.getCompileOutputArtifact(
-            ruleContext,
-            CppHelper.getArtifactNameForCategory(
-                ruleContext, ccToolchain, outputCategory, outputName),
-            configuration);
-        builder.setOutputs(ruleContext, outputCategory, outputName, generateDotd);
-        String gcnoFileName = CppHelper.getArtifactNameForCategory(ruleContext,
-            ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName);
-
-        // Create non-PIC compile actions
-        Artifact gcnoFile =
-            !CppHelper.isLipoOptimization(cppConfiguration, ccToolchain) && enableCoverage
-                ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
-                : null;
-
-        Artifact noPicDwoFile = generateDwo ? getDwoFile(noPicOutputFile) : null;
-        Artifact ltoIndexingFile =
-            bitcodeOutput ? getLtoIndexingFile(builder.getOutputFile()) : null;
-
-        setupCompileBuildVariables(
-            builder,
-            sourceLabel,
-            /* usePic= */ false,
-            ccRelativeName,
-            sourceArtifact.getExecPath(),
-            gcnoFile,
-            noPicDwoFile,
-            ltoIndexingFile,
-            cppModuleMap);
-
-        if (maySaveTemps) {
-          result.addTemps(
-              createTempsActions(
-                  sourceArtifact,
-                  sourceLabel,
-                  outputName,
-                  builder,
-                  /* usePic= */ false,
-                  generateDotd,
-                  ccRelativeName));
-        }
-
-        builder.setGcnoFile(gcnoFile);
-        builder.setDwoFile(noPicDwoFile);
-        builder.setLtoIndexingFile(ltoIndexingFile);
-
-        semantics.finalizeCompileActionBuilder(ruleContext, builder);
-        CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
-        env.registerAction(compileAction);
-        Artifact objectFile = compileAction.getOutputFile();
-        directOutputs.add(objectFile);
-        if (addObject) {
-          result.addObjectFile(objectFile);
-          if (bitcodeOutput) {
-            result.addLtoBitcodeFile(objectFile, ltoIndexingFile);
-          }
-        }
-        if (noPicDwoFile != null) {
-          // Host targets don't produce .dwo files.
-          result.addDwoFile(noPicDwoFile);
-        }
-        if (cppConfiguration.isLipoContextCollector()) {
-          result.addLipoScannable(compileAction);
-        }
-      }
-    }
-    return directOutputs.build();
-  }
-
-  private Artifact createCompileActionTemplate(
-      AnalysisEnvironment env,
-      CppSource source,
-      CppCompileActionBuilder builder,
-      Iterable<ArtifactCategory> outputCategories,
-      boolean usePic) {
-    SpecialArtifact sourceArtifact = (SpecialArtifact) source.getSource();
-    SpecialArtifact outputFiles =
-        CppHelper.getCompileOutputTreeArtifact(ruleContext, sourceArtifact, usePic);
-    // TODO(rduan): Dotd file output is not supported yet.
-    builder.setOutputs(outputFiles, /* dotdFile= */ null);
-    setupCompileBuildVariables(
-        builder,
-        source.getLabel(),
-        usePic,
-        /* ccRelativeName= */ null,
-        /* autoFdoImportPath= */ null,
-        /* gcnoFile= */ null,
-        /* dwoFile= */ null,
-        /* ltoIndexingFile= */ null,
-        builder.getContext().getCppModuleMap());
-    semantics.finalizeCompileActionBuilder(ruleContext, builder);
-    // Make sure this builder doesn't reference ruleContext outside of analysis phase.
-    CppCompileActionTemplate actionTemplate =
-        new CppCompileActionTemplate(
-            sourceArtifact,
-            outputFiles,
-            builder,
-            ccToolchain,
-            outputCategories,
-            ruleContext.getActionOwner());
-    env.registerAction(actionTemplate);
-
-    return outputFiles;
-  }
-
-  String getOutputNameBaseWith(String base, boolean usePic) throws RuleErrorException {
-    return usePic
-        ? CppHelper.getArtifactNameForCategory(
-            ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, base)
-        : base;
-  }
-
-  private void createFakeSourceAction(
-      Label sourceLabel,
-      String outputName,
-      CcCompilationOutputs.Builder result,
-      AnalysisEnvironment env,
-      CppCompileActionBuilder builder,
-      ArtifactCategory outputCategory,
-      boolean addObject,
-      PathFragment ccRelativeName,
-      PathFragment execPath,
-      boolean usePic,
-      boolean generateDotd)
-      throws RuleErrorException {
-    String outputNameBase = getOutputNameBaseWith(outputName, usePic);
-    String tempOutputName = ruleContext.getConfiguration().getBinFragment()
-        .getRelative(CppHelper.getObjDirectory(ruleContext.getLabel()))
-        .getRelative(
-            CppHelper.getArtifactNameForCategory(ruleContext, ccToolchain, outputCategory,
-                getOutputNameBaseWith(outputName + ".temp", usePic)))
-        .getPathString();
-    builder
-        .setPicMode(usePic)
-        .setOutputs(ruleContext, outputCategory, outputNameBase, generateDotd)
-        .setTempOutputFile(PathFragment.create(tempOutputName));
-
-    setupCompileBuildVariables(
-        builder,
-        sourceLabel,
-        usePic,
-        ccRelativeName,
-        execPath,
-        /* gcnoFile= */ null,
-        /* dwoFile= */ null,
-        /* ltoIndexingFile= */ null,
-        builder.getContext().getCppModuleMap());
-    semantics.finalizeCompileActionBuilder(ruleContext, builder);
-    CppCompileAction action = builder.buildOrThrowRuleError(ruleContext);
-    env.registerAction(action);
-    if (addObject) {
-      if (usePic) {
-        result.addPicObjectFile(action.getOutputFile());
-      } else {
-        result.addObjectFile(action.getOutputFile());
-      }
-    }
-  }
-
-  /**
-   * Returns the linked artifact resulting from a linking of the given type. Consults the feature
-   * configuration to obtain an action_config that provides the artifact. If the feature
-   * configuration provides no artifact, uses a default.
-   *
-   * <p>We cannot assume that the feature configuration contains an action_config for the link
-   * action, because the linux link action depends on hardcoded values in
-   * LinkCommandLine.getRawLinkArgv(), which are applied on the condition that an action_config is
-   * not present.
-   * TODO(b/30393154): Assert that the given link action has an action_config.
-   *
-   * @throws RuleErrorException
-   */
-  private Artifact getLinkedArtifact(LinkTargetType linkTargetType) throws RuleErrorException {
-    Artifact result = null;
-    Artifact linuxDefault =
-        CppHelper.getLinuxLinkedArtifact(
-            ruleContext, configuration, linkTargetType, linkedArtifactNameSuffix);
-
-    try {
-      String maybePicName = ruleContext.getLabel().getName() + linkedArtifactNameSuffix;
-      if (linkTargetType.picness() == Picness.PIC) {
-        maybePicName = CppHelper.getArtifactNameForCategory(
-            ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, maybePicName);
-      }
-      String linkedName = CppHelper.getArtifactNameForCategory(
-          ruleContext, ccToolchain, linkTargetType.getLinkerOutput(), maybePicName);
-      PathFragment artifactFragment = PathFragment.create(ruleContext.getLabel().getName())
-          .getParentDirectory().getRelative(linkedName);
-
-      result = ruleContext.getPackageRelativeArtifact(
-          artifactFragment, configuration.getBinDirectory(ruleContext.getRule().getRepository()));
-    } catch (ExpansionException e) {
-      ruleContext.throwWithRuleError(e.getMessage());
-    }
-
-    // If the linked artifact is not the linux default, then a FailAction is generated for the
-    // linux default to satisfy the requirement of the implicit output.
-    // TODO(b/30132703): Remove the implicit outputs of cc_library.
-    if (!result.equals(linuxDefault)) {
-      ruleContext.registerAction(
-          new FailAction(
-              ruleContext.getActionOwner(),
-              ImmutableList.of(linuxDefault),
-              String.format(
-                  "the given toolchain supports creation of %s instead of %s",
-                  linuxDefault.getExecPathString(), result.getExecPathString())));
-    }
-
-    return result;
-  }
-
-  /**
-   * Constructs the C++ linker actions. It generally generates two actions, one for a static library
-   * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
-   * it additionally creates a third action to generate a PIC static library.
-   *
-   * <p>For dynamic libraries, this method can additionally create an interface shared library that
-   * can be used for linking, but doesn't contain any executable code. This increases the number of
-   * cache hits for link actions. Call {@link #setAllowInterfaceSharedObjects(boolean)} to enable
-   * this behavior.
-   *
-   * @throws RuleErrorException
-   */
-  public CcLinkingOutputs createCcLinkActions(
-      CcCompilationOutputs ccOutputs, Iterable<Artifact> nonCodeLinkerInputs)
-      throws RuleErrorException, InterruptedException {
-    // For now only handle static links. Note that the dynamic library link below ignores linkType.
-    // TODO(bazel-team): Either support non-static links or move this check to setStaticLinkType().
-    Preconditions.checkState(
-        linkType.staticness() == Staticness.STATIC, "can only handle static links");
-
-    CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder();
-    if (cppConfiguration.isLipoContextCollector()) {
-      // Don't try to create LIPO link actions in collector mode,
-      // because it needs some data that's not available at this point.
-      return result.build();
-    }
-    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
-    boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ true);
-    boolean usePicForSharedLibs =
-        CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ false);
-
-    PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName());
-    String libraryIdentifier =
-        ruleContext
-            .getPackageDirectory()
-            .getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
-            .getPathString();
-
-    if (createStaticLibraries) {
-      createStaticLibraries(
-          result,
-          env,
-          usePicForBinaries,
-          usePicForSharedLibs,
-          libraryIdentifier,
-          ccOutputs,
-          nonCodeLinkerInputs);
-    }
-
-    if (createDynamicLibrary) {
-      createDynamicLibrary(result, env, usePicForSharedLibs, libraryIdentifier, ccOutputs);
-    }
-
-    return result.build();
-  }
-
-  private void createStaticLibraries(
-      CcLinkingOutputs.Builder result,
-      AnalysisEnvironment env,
-      boolean usePicForBinaries,
-      boolean usePicForSharedLibs,
-      String libraryIdentifier,
-      CcCompilationOutputs ccOutputs,
-      Iterable<Artifact> nonCodeLinkerInputs)
-      throws RuleErrorException, InterruptedException {
-    // Create static library (.a). The linkType only reflects whether the library is alwayslink or
-    // not. The PIC-ness is determined by whether we need to use PIC or not. There are three cases
-    // for (usePicForSharedLibs usePicForBinaries):
-    //
-    // (1) (false false) -> no pic code
-    // (2) (true false)  -> shared libraries as pic, but not binaries
-    // (3) (true true)   -> both shared libraries and binaries as pic
-    //
-    // In case (3), we always need PIC, so only create one static library containing the PIC
-    // object
-    // files. The name therefore does not match the content.
-    //
-    // Presumably, it is done this way because the .a file is an implicit output of every
-    // cc_library
-    // rule, so we can't use ".pic.a" that in the always-PIC case.
-
-    // If the crosstool is configured to select an output artifact, we use that selection.
-    // Otherwise, we use linux defaults.
-    Artifact linkedArtifact = getLinkedArtifact(linkType);
-
-    CppLinkAction maybePicAction =
-        newLinkActionBuilder(linkedArtifact)
-            .addObjectFiles(ccOutputs.getObjectFiles(usePicForBinaries))
-            .addNonCodeInputs(nonCodeLinkerInputs)
-            .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
-            .setLinkType(linkType)
-            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
-            .addActionInputs(linkActionInputs)
-            .setLibraryIdentifier(libraryIdentifier)
-            .addVariablesExtensions(variablesExtensions)
-            .build();
-    env.registerAction(maybePicAction);
-    if (usePicForBinaries) {
-      result.addPicStaticLibrary(maybePicAction.getOutputLibrary());
-    } else {
-      result.addStaticLibrary(maybePicAction.getOutputLibrary());
-      // Create a second static library (.pic.a). Only in case (2) do we need both PIC and non-PIC
-      // static libraries. In that case, the first static library contains the non-PIC code, and
-      // this
-      // one contains the PIC code, so the names match the content.
-      if (usePicForSharedLibs) {
-        LinkTargetType picLinkType =
-            (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY)
-                ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY
-                : LinkTargetType.PIC_STATIC_LIBRARY;
-
-        // If the crosstool is configured to select an output artifact, we use that selection.
-        // Otherwise, we use linux defaults.
-        Artifact picArtifact = getLinkedArtifact(picLinkType);
-        CppLinkAction picAction =
-            newLinkActionBuilder(picArtifact)
-                .addObjectFiles(ccOutputs.getObjectFiles(/* usePic= */ true))
-                .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
-                .setLinkType(picLinkType)
-                .setLinkStaticness(LinkStaticness.FULLY_STATIC)
-                .addActionInputs(linkActionInputs)
-                .setLibraryIdentifier(libraryIdentifier)
-                .addVariablesExtensions(variablesExtensions)
-                .build();
-        env.registerAction(picAction);
-        result.addPicStaticLibrary(picAction.getOutputLibrary());
-      }
-    }
-  }
-
-  private void createDynamicLibrary(
-      CcLinkingOutputs.Builder result,
-      AnalysisEnvironment env,
-      boolean usePicForSharedLibs,
-      String libraryIdentifier,
-      CcCompilationOutputs ccOutputs)
-      throws RuleErrorException, InterruptedException {
-    // Create dynamic library.
-    Artifact soImpl;
-    String mainLibraryIdentifier;
-    if (soImplArtifact == null) {
-      // If the crosstool is configured to select an output artifact, we use that selection.
-      // Otherwise, we use linux defaults.
-      soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY);
-      mainLibraryIdentifier = libraryIdentifier;
-    } else {
-      // This branch is only used for vestigial Google-internal rules where the name of the output
-      // file is explicitly specified in the BUILD file and as such, is platform-dependent. Thus,
-      // we just hardcode some reasonable logic to compute the library identifier and hope that this
-      // will eventually go away.
-      soImpl = soImplArtifact;
-      mainLibraryIdentifier = FileSystemUtils.removeExtension(
-          soImpl.getRootRelativePath().getPathString());
-
-    }
-
-    List<String> sonameLinkopts = ImmutableList.of();
-    Artifact soInterface = null;
-    if (CppHelper.useInterfaceSharedObjects(cppConfiguration, ccToolchain)
-        && allowInterfaceSharedObjects) {
-      soInterface =
-          CppHelper.getLinuxLinkedArtifact(
-              ruleContext,
-              configuration,
-              LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
-              linkedArtifactNameSuffix);
-      // TODO(b/28946988): Remove this hard-coded flag.
-      if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
-        sonameLinkopts =
-            ImmutableList.of(
-                "-Wl,-soname="
-                    + SolibSymlinkAction.getDynamicLibrarySoname(
-                        soImpl.getRootRelativePath(), /* preserveName= */ false));
-      }
-    }
-
-    CppLinkActionBuilder dynamicLinkActionBuilder =
-        newLinkActionBuilder(soImpl)
-            .setInterfaceOutput(soInterface)
-            .addObjectFiles(ccOutputs.getObjectFiles(usePicForSharedLibs))
-            .addNonCodeInputs(ccOutputs.getHeaderTokenFiles())
-            .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
-            .setLinkType(LinkTargetType.DYNAMIC_LIBRARY)
-            .setLinkStaticness(LinkStaticness.DYNAMIC)
-            .addActionInputs(linkActionInputs)
-            .setLibraryIdentifier(mainLibraryIdentifier)
-            .addLinkopts(linkopts)
-            .addLinkopts(sonameLinkopts)
-            .setRuntimeInputs(
-                ArtifactCategory.DYNAMIC_LIBRARY,
-                ccToolchain.getDynamicRuntimeLinkMiddleman(),
-                ccToolchain.getDynamicRuntimeLinkInputs())
-            .addVariablesExtensions(variablesExtensions);
-
-    if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
-      // On Windows, we cannot build a shared library with symbols unresolved, so here we
-      // dynamically
-      // link to all it's dependencies.
-      CcLinkParams.Builder ccLinkParamsBuilder =
-          CcLinkParams.builder(/* linkingStatically= */ false, /* linkShared= */ true);
-      ccLinkParamsBuilder.addCcLibrary(ruleContext);
-      dynamicLinkActionBuilder.addLinkParams(ccLinkParamsBuilder.build(), ruleContext);
-
-      // If windows_export_all_symbols feature is enabled, bazel parses object files to generate
-      // DEF file and use it to export symbols. The generated DEF file won't be used if a custom
-      // DEF file is specified by win_def_file attribute.
-      if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) {
-        Artifact generatedDefFile =
-            CppHelper.createDefFileActions(
-                ruleContext,
-                ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST),
-                ccOutputs.getObjectFiles(false),
-                SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), true));
-        dynamicLinkActionBuilder.setDefFile(generatedDefFile);
-      }
-
-      // If user specifies a custom DEF file, then we use this one instead of the generated one.
-      Artifact customDefFile = null;
-      if (ruleContext.isAttrDefined("win_def_file", LABEL)) {
-        customDefFile = ruleContext.getPrerequisiteArtifact("win_def_file", Mode.TARGET);
-      }
-      if (customDefFile != null) {
-        dynamicLinkActionBuilder.setDefFile(customDefFile);
-      }
-    }
-
-    if (!ccOutputs.getLtoBitcodeFiles().isEmpty()
-        && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
-      dynamicLinkActionBuilder.setLtoIndexing(true);
-      dynamicLinkActionBuilder.setUsePicForLtoBackendActions(usePicForSharedLibs);
-      CppLinkAction indexAction = dynamicLinkActionBuilder.build();
-      if (indexAction != null) {
-        env.registerAction(indexAction);
-      }
-
-      dynamicLinkActionBuilder.setLtoIndexing(false);
-    }
-
-    CppLinkAction dynamicLinkAction = dynamicLinkActionBuilder.build();
-    env.registerAction(dynamicLinkAction);
-
-    LibraryToLink dynamicLibrary = dynamicLinkAction.getOutputLibrary();
-    LibraryToLink interfaceLibrary = dynamicLinkAction.getInterfaceOutputLibrary();
-
-    // If shared library has neverlink=1, then leave it untouched. Otherwise,
-    // create a mangled symlink for it and from now on reference it through
-    // mangled name only.
-    //
-    // When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, we don't need to create the special
-    // solibDir, instead we use the original interface library and dynamic library.
-    if (neverLink
-        || featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
-      result.addDynamicLibrary(interfaceLibrary == null ? dynamicLibrary : interfaceLibrary);
-      result.addExecutionDynamicLibrary(dynamicLibrary);
-    } else {
-      Artifact implLibraryLinkArtifact =
-          SolibSymlinkAction.getDynamicLibrarySymlink(
-              ruleContext,
-              ccToolchain.getSolibDirectory(),
-              dynamicLibrary.getArtifact(),
-              /* preserveName= */ false,
-              /* prefixConsumer= */ false,
-              ruleContext.getConfiguration());
-      LibraryToLink implLibraryLink =
-          LinkerInputs.solibLibraryToLink(
-              implLibraryLinkArtifact, dynamicLibrary.getArtifact(), libraryIdentifier);
-      result.addExecutionDynamicLibrary(implLibraryLink);
-
-      LibraryToLink libraryLink;
-      if (interfaceLibrary == null) {
-        libraryLink = implLibraryLink;
-      } else {
-        Artifact libraryLinkArtifact =
-            SolibSymlinkAction.getDynamicLibrarySymlink(
-                ruleContext,
-                ccToolchain.getSolibDirectory(),
-                interfaceLibrary.getArtifact(),
-                /* preserveName= */ false,
-                /* prefixConsumer= */ false,
-                ruleContext.getConfiguration());
-        libraryLink =
-            LinkerInputs.solibLibraryToLink(
-                libraryLinkArtifact, interfaceLibrary.getArtifact(), libraryIdentifier);
-      }
-      result.addDynamicLibrary(libraryLink);
-    }
-  }
-
-
-  private CppLinkActionBuilder newLinkActionBuilder(Artifact outputArtifact) {
-    return new CppLinkActionBuilder(
-            ruleContext, outputArtifact, ccToolchain, fdoSupport, featureConfiguration, semantics)
-        .setCrosstoolInputs(ccToolchain.getLink())
-        .addNonCodeInputs(context.getTransitiveCompilationPrerequisites());
-  }
-
-  /**
-   * Creates a basic cpp compile action builder for source file. Configures options, crosstool
-   * inputs, output and dotd file names, compilation context and copts.
-   */
-  private CppCompileActionBuilder createCompileActionBuilder(Artifact source) {
-    CppCompileActionBuilder builder =
-        new CppCompileActionBuilder(ruleContext, ccToolchain, configuration);
-    builder.setSourceFile(source);
-    builder.setContext(context);
-    builder.addEnvironment(ccToolchain.getEnvironment());
-    builder.setCoptsFilter(coptsFilter);
-    return builder;
-  }
-
-  /**
-   * Creates cpp PIC compile action builder from the given builder by adding necessary copt and
-   * changing output and dotd file names.
-   */
-  private CppCompileActionBuilder copyAsPicBuilder(
-      CppCompileActionBuilder builder,
-      String outputName,
-      ArtifactCategory outputCategory,
-      boolean generateDotd)
-      throws RuleErrorException {
-    CppCompileActionBuilder picBuilder = new CppCompileActionBuilder(builder);
-    picBuilder
-        .setPicMode(true)
-        .setOutputs(ruleContext, outputCategory, outputName, generateDotd);
-
-    return picBuilder;
-  }
-
-  /** Create the actions for "--save_temps". */
-  private ImmutableList<Artifact> createTempsActions(
-      Artifact source,
-      Label sourceLabel,
-      String outputName,
-      CppCompileActionBuilder builder,
-      boolean usePic,
-      boolean generateDotd,
-      PathFragment ccRelativeName)
-      throws RuleErrorException {
-    if (!cppConfiguration.getSaveTemps()) {
-      return ImmutableList.of();
-    }
-
-    String path = source.getFilename();
-    boolean isCFile = CppFileTypes.C_SOURCE.matches(path);
-    boolean isCppFile = CppFileTypes.CPP_SOURCE.matches(path);
-
-    if (!isCFile && !isCppFile) {
-      return ImmutableList.of();
-    }
-
-    ArtifactCategory category = isCFile
-        ? ArtifactCategory.PREPROCESSED_C_SOURCE : ArtifactCategory.PREPROCESSED_CPP_SOURCE;
-
-    String outputArtifactNameBase = getOutputNameBaseWith(outputName, usePic);
-
-    CppCompileActionBuilder dBuilder = new CppCompileActionBuilder(builder);
-    dBuilder.setOutputs(ruleContext, category, outputArtifactNameBase, generateDotd);
-    setupCompileBuildVariables(
-        dBuilder,
-        sourceLabel,
-        usePic,
-        ccRelativeName,
-        source.getExecPath(),
-        /* gcnoFile= */ null,
-        /* dwoFile= */ null,
-        /* ltoIndexingFile= */ null,
-        builder.getContext().getCppModuleMap());
-    semantics.finalizeCompileActionBuilder(ruleContext, dBuilder);
-    CppCompileAction dAction = dBuilder.buildOrThrowRuleError(ruleContext);
-    ruleContext.registerAction(dAction);
-
-    CppCompileActionBuilder sdBuilder = new CppCompileActionBuilder(builder);
-    sdBuilder.setOutputs(
-        ruleContext, ArtifactCategory.GENERATED_ASSEMBLY, outputArtifactNameBase, generateDotd);
-    setupCompileBuildVariables(
-        sdBuilder,
-        sourceLabel,
-        usePic,
-        ccRelativeName,
-        source.getExecPath(),
-        /* gcnoFile= */ null,
-        /* dwoFile= */ null,
-        /* ltoIndexingFile= */ null,
-        builder.getContext().getCppModuleMap());
-    semantics.finalizeCompileActionBuilder(ruleContext, sdBuilder);
-    CppCompileAction sdAction = sdBuilder.buildOrThrowRuleError(ruleContext);
-    ruleContext.registerAction(sdAction);
-
-    return ImmutableList.of(
-        dAction.getOutputFile(),
-        sdAction.getOutputFile());
-  }
-
-  /**
-   * Returns true iff code coverage is enabled for the given target.
-   */
-  private boolean isCodeCoverageEnabled() {
-    if (configuration.isCodeCoverageEnabled()) {
-      // If rule is matched by the instrumentation filter, enable instrumentation
-      if (InstrumentedFilesCollector.shouldIncludeLocalSources(ruleContext)) {
-        return true;
-      }
-      // At this point the rule itself is not matched by the instrumentation filter. However, we
-      // might still want to instrument C++ rules if one of the targets listed in "deps" is
-      // instrumented and, therefore, can supply header files that we would want to collect code
-      // coverage for. For example, think about cc_test rule that tests functionality defined in a
-      // header file that is supplied by the cc_library.
-      //
-      // Note that we only check direct prerequisites and not the transitive closure. This is done
-      // for two reasons:
-      // a) It is a good practice to declare libraries which you directly rely on. Including headers
-      //    from a library hidden deep inside the transitive closure makes build dependencies less
-      //    readable and can lead to unexpected breakage.
-      // b) Traversing the transitive closure for each C++ compile action would require more complex
-      //    implementation (with caching results of this method) to avoid O(N^2) slowdown.
-      if (ruleContext.getRule().isAttrDefined("deps", BuildType.LABEL_LIST)) {
-        for (TransitiveInfoCollection dep : ruleContext.getPrerequisites("deps", Mode.TARGET)) {
-          if (dep.getProvider(CppCompilationContext.class) != null
-              && InstrumentedFilesCollector.shouldIncludeLocalSources(configuration, dep)) {
-            return true;
-          }
-        }
-      }
-    }
-    return false;
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
index 2f4e780..bce029f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
@@ -273,7 +273,7 @@
       // TODO(dougk): Configure output artifact with action_config
       // once proto compile action is configurable from the crosstool.
       if (!ccToolchain(ruleContext).supportsDynamicLinker()) {
-        helper.setCreateDynamicLibrary(false);
+        helper.setShouldCreateDynamicLibrary(false);
       }
       return helper;
     }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CompileBuildVariablesTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CompileBuildVariablesTest.java
index 89b7a3b..cbcca08 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CompileBuildVariablesTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CompileBuildVariablesTest.java
@@ -59,9 +59,9 @@
 
     Variables variables = getCompileBuildVariables("//x:bin", "bin");
 
-    assertThat(variables.getStringVariable(CppModel.SOURCE_FILE_VARIABLE_NAME))
+    assertThat(variables.getStringVariable(CcCompilationHelper.SOURCE_FILE_VARIABLE_NAME))
         .contains("x/bin.cc");
-    assertThat(variables.getStringVariable(CppModel.OUTPUT_FILE_VARIABLE_NAME))
+    assertThat(variables.getStringVariable(CcCompilationHelper.OUTPUT_FILE_VARIABLE_NAME))
         .contains("x/bin");
   }
 
@@ -76,7 +76,7 @@
     Variables variables = getCompileBuildVariables("//x:bin", "bin");
 
     ImmutableList<String> copts =
-        Variables.toStringList(variables, CppModel.LEGACY_COMPILE_FLAGS_VARIABLE_NAME);
+        Variables.toStringList(variables, CcCompilationHelper.LEGACY_COMPILE_FLAGS_VARIABLE_NAME);
     assertThat(copts).contains("-foo");
   }
 
@@ -91,7 +91,7 @@
     Variables variables = getCompileBuildVariables("//x:bin", "bin");
 
     ImmutableList<String> copts =
-        Variables.toStringList(variables, CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME);
+        Variables.toStringList(variables, CcCompilationHelper.USER_COMPILE_FLAGS_VARIABLE_NAME);
     assertThat(copts).contains("-foo");
   }
 
@@ -108,7 +108,8 @@
     Variables variables = getCompileBuildVariables("//x:bin", "bin");
 
     ImmutableList<String> unfilteredCompileFlags =
-        Variables.toStringList(variables, CppModel.UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME);
+        Variables.toStringList(
+            variables, CcCompilationHelper.UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME);
     assertThat(unfilteredCompileFlags).contains("--i_ll_live_forever");
   }
 
@@ -121,7 +122,7 @@
     Variables variables = getCompileBuildVariables("//x:bin", "bin");
 
     ImmutableList<String> copts =
-        Variables.toStringList(variables, CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME);
+        Variables.toStringList(variables, CcCompilationHelper.USER_COMPILE_FLAGS_VARIABLE_NAME);
     assertThat(copts).containsExactly("-foo").inOrder();
   }
 
@@ -137,7 +138,7 @@
 
     Variables variables = getCompileBuildVariables("//x:bin", "bin");
 
-    assertThat(variables.getStringVariable(CppModel.SYSROOT_VARIABLE_NAME))
+    assertThat(variables.getStringVariable(CcCommon.SYSROOT_VARIABLE_NAME))
         .isEqualTo("/usr/local/custom-sysroot");
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java
index 1f039cf..b467a7f 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java
@@ -263,6 +263,6 @@
     ConfiguredTarget testTarget = getConfiguredTarget("//x:foo");
     Variables testVariables = getLinkBuildVariables(testTarget, LinkTargetType.EXECUTABLE);
 
-    assertThat(testVariables.isAvailable(CppModel.SYSROOT_VARIABLE_NAME)).isTrue();
+    assertThat(testVariables.isAvailable(CcCommon.SYSROOT_VARIABLE_NAME)).isTrue();
   }
 }