Rollback of commit f61d12e9e4f940810efbaf244911a94830ba6c05.

*** Reason for rollback ***

--
MOS_MIGRATED_REVID=129078102
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 f25fc94..a763713 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
@@ -228,6 +228,10 @@
     linkActionBuilder.setLinkStaticness(linkStaticness);
     linkActionBuilder.setFake(fake);
     linkActionBuilder.setFeatureConfiguration(featureConfiguration);
+    CcToolchainFeatures.Variables.Builder buildVariables =
+        new CcToolchainFeatures.Variables.Builder();
+    buildVariables.addAllVariables(CppHelper.getToolchain(ruleContext).getBuildVariables());
+    linkActionBuilder.setBuildVariables(buildVariables.build());
 
     if (CppLinkAction.enableSymbolsCounts(cppConfiguration, fake, linkType)) {
       linkActionBuilder.setSymbolCountsOutput(ruleContext.getPackageRelativeArtifact(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java
index f935b4f..9ba846a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java
@@ -33,6 +33,7 @@
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain;
 import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain.Tool;
+
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
@@ -755,17 +756,15 @@
    */
   @Immutable
   public static class Variables {
-   
-    /** An empty variables instance. */
-    public static final Variables EMPTY = new Variables.Builder().build();
-
+    
     /**
-     * Variables can be set as an arbitrarily deeply nested recursive sequence, which we represent
-     * as a tree of {@code Sequence} nodes. The nodes are {@code NestedSequence} objects, while the
-     * leafs are {@code ValueSequence} objects. We do not allow {@code Value} objects in the tree,
-     * as the object memory overhead is too large when we have millions of values. If we find single
-     * element {@code ValueSequence} in memory profiles in the future, we can introduce another
-     * special case type.
+     * Variables can be set as an arbitrarily deeply nested recursive sequence, which
+     * we represent as a tree of {@code Sequence} nodes.
+     * The nodes are {@code NestedSequence} objects, while the leafs are {@code ValueSequence}
+     * objects. We do not allow {@code Value} objects in the tree, as the object memory overhead
+     * is too large when we have millions of values.
+     * If we find single element {@code ValueSequence} in memory profiles in the future, we
+     * can introduce another special case type.
      */
     interface Sequence {
 
@@ -1090,8 +1089,10 @@
       return new NestedView(viewMap, sequenceName, sequenceVariables.get(sequenceName));
     }
 
-    /** Returns whether {@code variable} is set. */
-    boolean isAvailable(String variable) {
+    /**
+     * Returns whether {@code variable} is set.
+     */
+    private boolean isAvailable(String variable) {
       return variables.containsKey(variable) || sequenceVariables.containsKey(variable);
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
index 03212b9..1e14df9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
@@ -38,7 +38,6 @@
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader.CppConfigurationParameters;
-import com.google.devtools.build.lib.rules.cpp.CppLinkActionConfigs.CppLinkPlatform;
 import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -54,6 +53,7 @@
 import com.google.devtools.common.options.OptionsParsingException;
 import com.google.protobuf.TextFormat;
 import com.google.protobuf.TextFormat.ParseException;
+
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.EnumSet;
@@ -683,7 +683,6 @@
 
     return result.build();
   }
-  
   private boolean linkActionsAreConfigured(CToolchain toolchain) {
     for (LinkTargetType type : LinkTargetType.values()) {
       boolean typeIsConfigured = false;
@@ -714,17 +713,6 @@
       return toolchain;
     }
     try {
-      if (!linkActionsAreConfigured(toolchain)) {
-        if (getTargetLibc().equals("macosx")) {
-          TextFormat.merge(
-              CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.MAC), toolchainBuilder);
-        } else {
-          TextFormat.merge(
-              CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.LINUX),
-              toolchainBuilder);
-        }
-      }
-
       if (!features.contains("dependency_file")) {
         // Gcc options:
         //  -MD turns on .d file output as a side-effect (doesn't imply -E)
@@ -869,8 +857,12 @@
                 + "  flag_set {"
                 + "    action: 'c-compile'"
                 + "    action: 'c++-compile'"
+                + "    action: 'c++-link-static-library'"
+                + "    action: 'c++-link-pic-static-library'"
                 + "    action: 'c++-link-interface-dynamic-library'"
                 + "    action: 'c++-link-dynamic-library'"
+                + "    action: 'c++-link-alwayslink-static-library'"
+                + "    action: 'c++-link-alwayslink-pic-static-library'"
                 + "    action: 'c++-link-executable'"
                 + "    flag_group {"
                 + "      flag: '-fprofile-generate=%{fdo_instrument_path}'"
@@ -956,8 +948,12 @@
                 + "    }"
                 + "  }"
                 + "  flag_set {"
+                + "    action: 'c++-link-static-library'"
+                + "    action: 'c++-link-pic-static-library'"
                 + "    action: 'c++-link-interface-dynamic-library'"
                 + "    action: 'c++-link-dynamic-library'"
+                + "    action: 'c++-link-always-link-static-library'"
+                + "    action: 'c++-link-always-link-pic-static-library'"
                 + "    action: 'c++-link-executable'"
                 + "    flag_group {"
                 + "      flag: '-lgcov'"
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
index cda2e26..3ec9843 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
@@ -17,7 +17,6 @@
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -38,8 +37,6 @@
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.packages.RuleErrorConsumer;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
 import com.google.devtools.build.lib.rules.cpp.CppLinkAction.Context;
 import com.google.devtools.build.lib.rules.cpp.CppLinkAction.LinkArtifactFactory;
 import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
@@ -48,6 +45,7 @@
 import com.google.devtools.build.lib.util.Preconditions;
 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.HashMap;
@@ -55,57 +53,11 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
 import javax.annotation.Nullable;
 
 /** Builder class to construct {@link CppLinkAction}s. */
 public class CppLinkActionBuilder {
-
-  /** A build variable for clang flags that set the root of the linker search path. */
-  public static final String RUNTIME_ROOT_FLAGS_VARIABLE = "runtime_root_flags";
-
-  /** A build variable for entries in the linker search path. */
-  public static final String RUNTIME_ROOT_ENTRIES_VARIABLE = "runtime_root_entries";
-
-  /**
-   * A build variable for options applying to specific libraries in the linker invocation that
-   * either identify a library to be linked or add a directory to the runtime library search path.
-   */
-  public static final String LIBOPTS_VARIABLE = "libopts";
-
-  /**
-   * A build variable for flags providing files to link as inputs in the linker invocation that
-   * should not go in a -whole_archive block.
-   */
-  public static final String LINKER_INPUT_PARAMS_VARIABLE = "linker_input_params";
-
-  /**
-   * A build variable for flags providing files to link as inputs in the linker invocation that
-   * should go in a -whole_archive block.
-   */
-  public static final String WHOLE_ARCHIVE_LINKER_INPUT_PARAMS_VARIABLE =
-      "whole_archive_linker_params";
-
-  /** A build variable whose presence indicates that whole archive flags should be applied. */
-  public static final String GLOBAL_WHOLE_ARCHIVE_VARIABLE = "global_whole_archive";
-
-  /** A build variable for the execpath of the output of the linker. */
-  public static final String OUTPUT_EXECPATH_VARIABLE = "output_execpath";
-
-  /**
-   * A build variable that is set to indicate a mostly static linking for which the linked binary
-   * should be piped to /dev/null.
-   */
-  public static final String SKIP_MOSTLY_STATIC_VARIABLE = "skip_mostly_static";
-
-  /** A build variable giving a path to which to write symbol counts. */
-  public static final String SYMBOL_COUNTS_OUTPUT_VARIABLE = "symbol_counts_output";
-
-  /** A build variable giving linkstamp paths. */
-  public static final String LINKSTAMP_PATHS_VARIABLE = "linkstamp_paths";
-
-  /** A build variable whose presence indicates that PIC code should be generated. */
-  public static final String FORCE_PIC_VARIABLE = "force_pic";
-
   // Builder-only
   // Null when invoked from tests (e.g. via createTestBuilder).
   @Nullable private final RuleContext ruleContext;
@@ -120,6 +72,8 @@
   protected final BuildConfiguration configuration;
   private final CppConfiguration cppConfiguration;
   private FeatureConfiguration featureConfiguration;
+  private CcToolchainFeatures.Variables buildVariables =
+      new CcToolchainFeatures.Variables.Builder().build();
 
   // Morally equivalent with {@link Context}, except these are mutable.
   // Keep these in sync with {@link Context}.
@@ -242,8 +196,10 @@
   private String getActionName() {
     return linkType.getActionName();
   }
-  
-  /** Returns linker inputs that are not libraries. */
+
+  /**
+   * Returns linker inputs that are not libraries.
+   */
   public Set<LinkerInput> getNonLibraries() {
     return nonLibraries;
   }
@@ -445,17 +401,6 @@
     final ImmutableSet<String> features =
         (ruleContext == null) ? ImmutableSet.<String>of() : ruleContext.getFeatures();
 
-    // For backwards compatibility, and for tests, we permit the link action to be
-    // instantiated without a feature configuration.
-    if (featureConfiguration == null) {
-      if (toolchain != null) {
-        featureConfiguration =
-            CcCommon.configureFeatures(ruleContext, toolchain, CcLibraryHelper.SourceCategory.CC);
-      } else {
-        featureConfiguration = CcCommon.configureFeatures(ruleContext);
-      }
-    }
-
     final LibraryToLink outputLibrary =
         LinkerInputs.newInputLibrary(output, filteredNonLibraryArtifacts, this.ltoBitcodeFiles);
     final LibraryToLink interfaceOutputLibrary =
@@ -491,24 +436,6 @@
               symbolCounts);
     }
 
-    ImmutableList<LinkerInput> runtimeLinkerInputs =
-        ImmutableList.copyOf(LinkerInputs.simpleLinkerInputs(runtimeInputs));
-
-    // Add build variables necessary to template link args into the crosstool.
-    Variables.Builder buildVariablesBuilder = new Variables.Builder();
-    CppLinkVariablesExtension variablesExtension =
-        isLTOIndexing
-            ? new CppLinkVariablesExtension(
-                linkstampMap, needWholeArchive, linkerInputs, runtimeLinkerInputs, null)
-            : new CppLinkVariablesExtension(
-                linkstampMap,
-                needWholeArchive,
-                linkerInputs,
-                runtimeLinkerInputs,
-                outputLibrary.getArtifact());
-    variablesExtension.addVariables(buildVariablesBuilder);
-    Variables buildVariables = buildVariablesBuilder.build();
-
     PathFragment paramRootPath =
         ParameterFile.derivePath(
             outputLibrary.getArtifact().getRootRelativePath(), (isLTOIndexing) ? "lto" : "2");
@@ -519,52 +446,28 @@
             ? linkArtifactFactory.create(ruleContext, configuration, paramRootPath)
             : null;
 
-    Preconditions.checkArgument(
-        linkType != LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
-        "you can't link an interface dynamic library directly");
-    if (linkType != LinkTargetType.DYNAMIC_LIBRARY) {
-      Preconditions.checkArgument(
-          interfaceOutput == null,
-          "interface output may only be non-null for dynamic library links");
-    }
-    if (linkType.isStaticLibraryLink()) {
-      // solib dir must be null for static links
-      runtimeSolibDir = null;
-
-      Preconditions.checkArgument(
-          linkStaticness == LinkStaticness.FULLY_STATIC, "static library link must be static");
-      Preconditions.checkArgument(
-          symbolCounts == null, "the symbol counts output must be null for static links");
-      Preconditions.checkArgument(
-          !isNativeDeps, "the native deps flag must be false for static links");
-      Preconditions.checkArgument(
-          !needWholeArchive, "the need whole archive flag must be false for static links");
-    }
-
     LinkCommandLine.Builder linkCommandLineBuilder =
         new LinkCommandLine.Builder(configuration, getOwner(), ruleContext)
+            .setActionName(getActionName())
             .setLinkerInputs(linkerInputs)
-            .setRuntimeInputs(runtimeLinkerInputs)
+            .setRuntimeInputs(ImmutableList.copyOf(LinkerInputs.simpleLinkerInputs(runtimeInputs)))
             .setLinkTargetType(linkType)
             .setLinkStaticness(linkStaticness)
             .setFeatures(features)
             .setRuntimeSolibDir(linkType.isStaticLibraryLink() ? null : runtimeSolibDir)
             .setNativeDeps(isNativeDeps)
             .setUseTestOnlyFlags(useTestOnlyFlags)
+            .setNeedWholeArchive(needWholeArchive)
             .setParamFile(paramFile)
+            .setAllLTOArtifacts(isLTOIndexing ? null : allLTOArtifacts)
             .setToolchain(toolchain)
-            .setBuildVariables(buildVariables)
             .setFeatureConfiguration(featureConfiguration);
 
-    // TODO(b/30228443): Refactor noWholeArchiveInputs into action_configs, and remove this.
-    if (needWholeArchive) {
-      linkCommandLineBuilder.setNoWholeArchiveFlags(variablesExtension.getNoWholeArchiveInputs());
-    }
-
     if (!isLTOIndexing) {
       linkCommandLineBuilder
           .setOutput(outputLibrary.getArtifact())
           .setInterfaceOutput(interfaceOutput)
+          .setSymbolCountsOutput(symbolCounts)
           .setBuildInfoHeaderArtifacts(buildInfoHeaderArtifacts)
           .setInterfaceSoBuilder(getInterfaceSoBuilder())
           .setLinkstamps(linkstampMap)
@@ -603,6 +506,13 @@
       dependencyInputsBuilder.addTransitive(compilationInputs.build());
     }
 
+    // For backwards compatibility, and for tests, we permit the link action to be
+    // instantiated without a feature configuration. In this case, an empty feature
+    // configuration is used.
+    if (featureConfiguration == null) {
+      this.featureConfiguration = new FeatureConfiguration();
+    }
+
     Iterable<Artifact> expandedInputs =
         LinkerInputs.toLibraryArtifacts(
             Link.mergeInputsDependencies(
@@ -635,7 +545,7 @@
       for (LTOBackendArtifacts a : allLTOArtifacts) {
         List<String> argv = new ArrayList<>();
         argv.addAll(cppConfiguration.getLinkOptions());
-        argv.addAll(featureConfiguration.getCommandLine(getActionName(), Variables.EMPTY));
+        argv.addAll(featureConfiguration.getCommandLine(getActionName(), buildVariables));
         argv.addAll(cppConfiguration.getCompilerOptions(features));
         a.setCommandLine(argv);
       }
@@ -774,6 +684,12 @@
     return this;
   }
 
+  /** Sets the build variables that will be used to template the crosstool. */
+  public CppLinkActionBuilder setBuildVariables(CcToolchainFeatures.Variables buildVariables) {
+    this.buildVariables = buildVariables;
+    return this;
+  }
+
   /**
    * This is the LTO indexing step, rather than the real link.
    *
@@ -1020,439 +936,4 @@
     this.runtimeSolibDir = runtimeSolibDir;
     return this;
   }
-
-  private static class LinkArgCollector {
-    String rpathRoot;
-    List<String> rpathEntries;
-    Set<String> libopts;
-    List<String> linkerInputParams;
-    List<String> wholeArchiveLinkerInputParams;
-    List<String> noWholeArchiveInputs;
-
-    public void setRpathRoot(String rPathRoot) {
-      this.rpathRoot = rPathRoot;
-    }
-
-    public void setRpathEntries(List<String> rpathEntries) {
-      this.rpathEntries = rpathEntries;
-    }
-
-    public void setLibopts(Set<String> libopts) {
-      this.libopts = libopts;
-    }
-
-    public void setLinkerInputParams(List<String> linkerInputParams) {
-      this.linkerInputParams = linkerInputParams;
-    }
-
-    public void setWholeArchiveLinkerInputParams(List<String> wholeArchiveInputParams) {
-      this.wholeArchiveLinkerInputParams = wholeArchiveInputParams;
-    }
-
-    public void setNoWholeArchiveInputs(List<String> noWholeArchiveInputs) {
-      this.noWholeArchiveInputs = noWholeArchiveInputs;
-    }
-
-    public String getRpathRoot() {
-      return rpathRoot;
-    }
-
-    public List<String> getRpathEntries() {
-      return rpathEntries;
-    }
-
-    public Set<String> getLibopts() {
-      return libopts;
-    }
-
-    public List<String> getLinkerInputParams() {
-      return linkerInputParams;
-    }
-
-    public List<String> getWholeArchiveLinkerInputParams() {
-      return wholeArchiveLinkerInputParams;
-    }
-
-    public List<String> getNoWholeArchiveInputs() {
-      return noWholeArchiveInputs;
-    }
-  }
-
-  private class CppLinkVariablesExtension implements VariablesExtension {
-
-    private final ImmutableMap<Artifact, Artifact> linkstampMap;
-    private final boolean needWholeArchive;
-    private final Iterable<LinkerInput> linkerInputs;
-    private final ImmutableList<LinkerInput> runtimeLinkerInputs;
-    private final Artifact outputArtifact;
-
-    private final LinkArgCollector linkArgCollector = new LinkArgCollector();
-
-    public CppLinkVariablesExtension(
-        ImmutableMap<Artifact, Artifact> linkstampMap,
-        boolean needWholeArchive,
-        Iterable<LinkerInput> linkerInputs,
-        ImmutableList<LinkerInput> runtimeLinkerInputs,
-        Artifact output) {
-      this.linkstampMap = linkstampMap;
-      this.needWholeArchive = needWholeArchive;
-      this.linkerInputs = linkerInputs;
-      this.runtimeLinkerInputs = runtimeLinkerInputs;
-      this.outputArtifact = output;
-
-      addInputFileLinkOptions(linkArgCollector);
-    }
-
-    /**
-     * Returns linker parameters indicating libraries that should not be linked inside a
-     * --whole_archive block.
-     *
-     * <p>TODO(b/30228443): Refactor into action configs
-     */
-    public List<String> getNoWholeArchiveInputs() {
-      return linkArgCollector.getNoWholeArchiveInputs();
-    }
-
-    @Override
-    public void addVariables(Variables.Builder buildVariables) {
-
-      // symbol counting
-      if (symbolCounts != null) {
-        buildVariables.addVariable(SYMBOL_COUNTS_OUTPUT_VARIABLE, symbolCounts.getExecPathString());
-      }
-
-      // linkstamp
-      ImmutableSet.Builder<String> linkstampPaths = ImmutableSet.<String>builder();
-      for (Artifact linkstampOutput : linkstampMap.values()) {
-        linkstampPaths.add(linkstampOutput.getExecPathString());
-      }
-
-      buildVariables.addSequenceVariable(LINKSTAMP_PATHS_VARIABLE, linkstampPaths.build());
-
-      // pic
-      boolean forcePic = cppConfiguration.forcePic();
-      if (forcePic) {
-        buildVariables.addVariable(FORCE_PIC_VARIABLE, "");
-      }
-
-      // rpath
-      if (linkArgCollector.getRpathRoot() != null) {
-        buildVariables.addVariable(RUNTIME_ROOT_FLAGS_VARIABLE, linkArgCollector.getRpathRoot());
-      }
-
-      if (linkArgCollector.getRpathEntries() != null) {
-        buildVariables.addSequenceVariable(
-            RUNTIME_ROOT_ENTRIES_VARIABLE, linkArgCollector.getRpathEntries());
-      }
-
-      buildVariables.addSequenceVariable(LIBOPTS_VARIABLE, linkArgCollector.getLibopts());
-      buildVariables.addSequenceVariable(
-          LINKER_INPUT_PARAMS_VARIABLE, linkArgCollector.getLinkerInputParams());
-      buildVariables.addSequenceVariable(
-          WHOLE_ARCHIVE_LINKER_INPUT_PARAMS_VARIABLE,
-          linkArgCollector.getWholeArchiveLinkerInputParams());
-
-      // global archive
-      if (needWholeArchive) {
-        buildVariables.addVariable(GLOBAL_WHOLE_ARCHIVE_VARIABLE, "");
-      }
-
-      // mostly static
-      if (linkStaticness == LinkStaticness.MOSTLY_STATIC && cppConfiguration.skipStaticOutputs()) {
-        buildVariables.addVariable(SKIP_MOSTLY_STATIC_VARIABLE, "");
-      }
-
-      // output exec path
-      if (this.outputArtifact != null) {
-        buildVariables.addVariable(
-            OUTPUT_EXECPATH_VARIABLE, this.outputArtifact.getExecPathString());
-      }
-
-      // Variables arising from the toolchain
-      buildVariables
-          .addAllVariables(CppHelper.getToolchain(ruleContext).getBuildVariables())
-          .build();
-      CppHelper.getFdoSupport(ruleContext).getLinkOptions(featureConfiguration, buildVariables);
-    }
-
-    private boolean isDynamicLibrary(LinkerInput linkInput) {
-      Artifact libraryArtifact = linkInput.getArtifact();
-      String name = libraryArtifact.getFilename();
-      return Link.SHARED_LIBRARY_FILETYPES.matches(name) && name.startsWith("lib");
-    }
-
-    private boolean isSharedNativeLibrary() {
-      return isNativeDeps && cppConfiguration.shareNativeDeps();
-    }
-
-    /**
-     * When linking a shared library fully or mostly static then we need to link in *all* dependent
-     * files, not just what the shared library needs for its own code. This is done by wrapping all
-     * objects/libraries with -Wl,-whole-archive and -Wl,-no-whole-archive. For this case the
-     * globalNeedWholeArchive parameter must be set to true. Otherwise only library objects (.lo)
-     * need to be wrapped with -Wl,-whole-archive and -Wl,-no-whole-archive.
-     *
-     * <p>TODO: Factor out of the bazel binary into build variables for crosstool action_configs.
-     */
-    private void addInputFileLinkOptions(LinkArgCollector linkArgCollector) {
-
-      // Used to collect -L and -Wl,-rpath options, ensuring that each used only once.
-      Set<String> libOpts = new LinkedHashSet<>();
-
-      // List of command line parameters to link input files (either directly or using -l).
-      List<String> linkerInputParameters = new ArrayList<>();
-
-      // List of command line parameters that need to be placed *outside* of
-      // --whole-archive ... --no-whole-archive.
-      List<String> noWholeArchiveInputs = new ArrayList<>();
-
-      PathFragment solibDir =
-          configuration
-              .getBinDirectory()
-              .getExecPath()
-              .getRelative(cppConfiguration.getSolibDirectory());
-      String runtimeSolibName = runtimeSolibDir != null ? runtimeSolibDir.getBaseName() : null;
-      boolean runtimeRpath =
-          runtimeSolibDir != null
-              && (linkType == LinkTargetType.DYNAMIC_LIBRARY
-                  || (linkType == LinkTargetType.EXECUTABLE
-                      && linkStaticness == LinkStaticness.DYNAMIC));
-
-      String rpathRoot = null;
-      List<String> runtimeRpathEntries = new ArrayList<>();
-
-      if (output != null) {
-        String origin =
-            useTestOnlyFlags && cppConfiguration.supportsExecOrigin()
-                ? "$EXEC_ORIGIN/"
-                : "$ORIGIN/";
-        if (runtimeRpath) {
-          runtimeRpathEntries.add("-Wl,-rpath," + origin + runtimeSolibName + "/");
-        }
-
-        // Calculate the correct relative value for the "-rpath" link option (which sets
-        // the search path for finding shared libraries).
-        if (isSharedNativeLibrary()) {
-          // For shared native libraries, special symlinking is applied to ensure C++
-          // runtimes are available under $ORIGIN/_solib_[arch]. So we set the RPATH to find
-          // them.
-          //
-          // Note that we have to do this because $ORIGIN points to different paths for
-          // different targets. In other words, blaze-bin/d1/d2/d3/a_shareddeps.so and
-          // blaze-bin/d4/b_shareddeps.so have different path depths. The first could
-          // reference a standard blaze-bin/_solib_[arch] via $ORIGIN/../../../_solib[arch],
-          // and the second could use $ORIGIN/../_solib_[arch]. But since this is a shared
-          // artifact, both are symlinks to the same place, so
-          // there's no *one* RPATH setting that fits all targets involved in the sharing.
-          rpathRoot =
-              "-Wl,-rpath," + origin + ":" + origin + cppConfiguration.getSolibDirectory() + "/";
-          if (runtimeRpath) {
-            runtimeRpathEntries.add("-Wl,-rpath," + origin + "../" + runtimeSolibName + "/");
-          }
-        } else {
-          // For all other links, calculate the relative path from the output file to _solib_[arch]
-          // (the directory where all shared libraries are stored, which resides under the blaze-bin
-          // directory. In other words, given blaze-bin/my/package/binary, rpathRoot would be
-          // "../../_solib_[arch]".
-          if (runtimeRpath) {
-            runtimeRpathEntries.add(
-                "-Wl,-rpath,"
-                    + origin
-                    + Strings.repeat("../", output.getRootRelativePath().segmentCount() - 1)
-                    + runtimeSolibName
-                    + "/");
-          }
-
-          rpathRoot =
-              "-Wl,-rpath,"
-                  + origin
-                  + Strings.repeat("../", output.getRootRelativePath().segmentCount() - 1)
-                  + cppConfiguration.getSolibDirectory()
-                  + "/";
-
-          if (isNativeDeps) {
-            // We also retain the $ORIGIN/ path to solibs that are in _solib_<arch>, as opposed to
-            // the package directory)
-            if (runtimeRpath) {
-              runtimeRpathEntries.add("-Wl,-rpath," + origin + "../" + runtimeSolibName + "/");
-            }
-            rpathRoot += ":" + origin;
-          }
-        }
-      }
-
-      boolean includeSolibDir = false;
-
-      Map<Artifact, Artifact> ltoMap = null;
-      if (!isLTOIndexing && (allLTOArtifacts != null)) {
-        // TODO(bazel-team): The LTO final link can only work if there are individual .o files on
-        // the command line. Rather than crashing, this should issue a nice error. We will get
-        // this by
-        // 1) moving supports_start_end_lib to a toolchain feature
-        // 2) having thin_lto require start_end_lib
-        // As a bonus, we can rephrase --nostart_end_lib as --features=-start_end_lib and get rid
-        // of a command line option.
-
-        Preconditions.checkState(cppConfiguration.useStartEndLib());
-        ltoMap = new HashMap<>();
-        for (LTOBackendArtifacts l : allLTOArtifacts) {
-          ltoMap.put(l.getBitcodeFile(), l.getObjectFile());
-        }
-      }
-
-      for (LinkerInput input : linkerInputs) {
-        if (isDynamicLibrary(input)) {
-          PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
-          Preconditions.checkState(
-              libDir.startsWith(solibDir),
-              "Artifact '%s' is not under directory '%s'.",
-              input.getArtifact(),
-              solibDir);
-          if (libDir.equals(solibDir)) {
-            includeSolibDir = true;
-          }
-          addDynamicInputLinkOptions(input, linkerInputParameters, libOpts, solibDir, rpathRoot);
-        } else {
-          addStaticInputLinkOptions(input, linkerInputParameters, ltoMap);
-        }
-      }
-
-      boolean includeRuntimeSolibDir = false;
-
-      for (LinkerInput input : runtimeLinkerInputs) {
-        List<String> optionsList = needWholeArchive ? noWholeArchiveInputs : linkerInputParameters;
-
-        if (isDynamicLibrary(input)) {
-          PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
-          Preconditions.checkState(
-              runtimeSolibDir != null && libDir.equals(runtimeSolibDir),
-              "Artifact '%s' is not under directory '%s'.",
-              input.getArtifact(),
-              solibDir);
-          includeRuntimeSolibDir = true;
-          addDynamicInputLinkOptions(input, optionsList, libOpts, solibDir, rpathRoot);
-        } else {
-          addStaticInputLinkOptions(input, optionsList, ltoMap);
-        }
-      }
-
-      // rpath ordering matters for performance; first add the one where most libraries are found.
-      if (includeSolibDir && rpathRoot != null) {
-        linkArgCollector.setRpathRoot(rpathRoot);
-      }
-      if (includeRuntimeSolibDir) {
-        linkArgCollector.setRpathEntries(runtimeRpathEntries);
-      }
-
-      linkArgCollector.setLibopts(libOpts);
-
-      ImmutableList.Builder<String> wholeArchiveInputParams = ImmutableList.builder();
-      ImmutableList.Builder<String> standardArchiveInputParams = ImmutableList.builder();
-      for (String param : linkerInputParameters) {
-        if (!wholeArchive && Link.LINK_LIBRARY_FILETYPES.matches(param)) {
-          wholeArchiveInputParams.add(param);
-        } else {
-          standardArchiveInputParams.add(param);
-        }
-      }
-
-      linkArgCollector.setLinkerInputParams(standardArchiveInputParams.build());
-      linkArgCollector.setWholeArchiveLinkerInputParams(wholeArchiveInputParams.build());
-      linkArgCollector.setNoWholeArchiveInputs(noWholeArchiveInputs);
-
-      if (ltoMap != null) {
-        Preconditions.checkState(ltoMap.isEmpty(), "Still have LTO objects left: %s", ltoMap);
-      }
-    }
-
-    /** Adds command-line options for a dynamic library input file into options and libOpts. */
-    private void addDynamicInputLinkOptions(
-        LinkerInput input,
-        List<String> options,
-        Set<String> libOpts,
-        PathFragment solibDir,
-        String rpathRoot) {
-      Preconditions.checkState(isDynamicLibrary(input));
-      Preconditions.checkState(!Link.useStartEndLib(input, cppConfiguration.archiveType()));
-
-      Artifact inputArtifact = input.getArtifact();
-      PathFragment libDir = inputArtifact.getExecPath().getParentDirectory();
-      if (rpathRoot != null
-          && !libDir.equals(solibDir)
-          && (runtimeSolibDir == null || !runtimeSolibDir.equals(libDir))) {
-        String dotdots = "";
-        PathFragment commonParent = solibDir;
-        while (!libDir.startsWith(commonParent)) {
-          dotdots += "../";
-          commonParent = commonParent.getParentDirectory();
-        }
-
-        libOpts.add(rpathRoot + dotdots + libDir.relativeTo(commonParent).getPathString());
-      }
-
-      libOpts.add("-L" + inputArtifact.getExecPath().getParentDirectory().getPathString());
-
-      String name = inputArtifact.getFilename();
-      if (CppFileTypes.SHARED_LIBRARY.matches(name)) {
-        String libName = name.replaceAll("(^lib|\\.(so|dylib)$)", "");
-        options.add("-l" + libName);
-      } else {
-        // Interface shared objects have a non-standard extension
-        // that the linker won't be able to find.  So use the
-        // filename directly rather than a -l option.  Since the
-        // library has an SONAME attribute, this will work fine.
-        options.add(inputArtifact.getExecPathString());
-      }
-    }
-
-    /**
-     * Adds command-line options for a static library or non-library input into options.
-     *
-     * @param ltoMap is a mutable list of exec paths that should be on the command-line, which must
-     *     be supplied for LTO final links.
-     */
-    private void addStaticInputLinkOptions(
-        LinkerInput input, List<String> options, @Nullable Map<Artifact, Artifact> ltoMap) {
-      Preconditions.checkState(!isDynamicLibrary(input));
-
-      // start-lib/end-lib library: adds its input object files.
-      if (Link.useStartEndLib(input, cppConfiguration.archiveType())) {
-        Iterable<Artifact> archiveMembers = input.getObjectFiles();
-        if (!Iterables.isEmpty(archiveMembers)) {
-          options.add("-Wl,--start-lib");
-          for (Artifact member : archiveMembers) {
-            if (ltoMap != null) {
-              Artifact backend = ltoMap.remove(member);
-
-              if (backend != null) {
-                // If the backend artifact is missing, we can't print a warning because this may
-                // happen normally, due libraries that list .o files explicitly, or generate .o
-                // files from assembler.
-                member = backend;
-              }
-            }
-
-            options.add(member.getExecPathString());
-          }
-          options.add("-Wl,--end-lib");
-        }
-      } else {
-        // For anything else, add the input directly.
-        Artifact inputArtifact = input.getArtifact();
-
-        if (ltoMap != null) {
-          Artifact ltoArtifact = ltoMap.remove(inputArtifact);
-          if (ltoArtifact != null) {
-            inputArtifact = ltoArtifact;
-          }
-        }
-
-        if (input.isFake()) {
-          options.add(Link.FAKE_OBJECT_PREFIX + inputArtifact.getExecPathString());
-        } else {
-          options.add(inputArtifact.getExecPathString());
-        }
-      }
-    }
-  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java
deleted file mode 100644
index a359350..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java
+++ /dev/null
@@ -1,297 +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 com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-
-/**
- * A helper class for creating action_configs for the c++ link action.
- *
- * <p>TODO(b/30109612): Replace this with action_configs in the crosstool instead of putting it in
- * legacy features.
- */
-public class CppLinkActionConfigs {
-
-  /** A platform for linker invocations. */
-  public static enum CppLinkPlatform {
-    LINUX,
-    MAC
-  }
-
-  public static String getCppLinkActionConfigs(CppLinkPlatform platform) {
-    return Joiner.on("\n")
-        .join(
-            ImmutableList.of(
-                "action_config {",
-                "   config_name: 'c++-link-executable'",
-                "   action_name: 'c++-link-executable'",
-                "   tool {",
-                "       tool_path: 'DUMMY_TOOL'",
-                "   }",
-                "   implies: 'symbol_counts'",
-                "   implies: 'linkstamps'",
-                "   implies: 'output_execpath_flags_executable'",
-                "   implies: 'global_whole_archive_open'",
-                "   implies: 'runtime_root_flags'",
-                "   implies: 'input_param_flags'",
-                "   implies: 'global_whole_archive_close'",
-                "   implies: 'force_pic_flags'",
-                "}",
-                "action_config {",
-                "   config_name: 'c++-link-dynamic-library'",
-                "   action_name: 'c++-link-dynamic-library'",
-                "   tool {",
-                "       tool_path: 'DUMMY_TOOL'",
-                "   }",
-                "   implies: 'symbol_counts'",
-                "   implies: 'shared_flag'",
-                "   implies: 'linkstamps'",
-                "   implies: 'output_execpath_flags'",
-                "   implies: 'global_whole_archive_open'",
-                "   implies: 'runtime_root_flags'",
-                "   implies: 'input_param_flags'",
-                "   implies: 'global_whole_archive_close'",
-                "}",
-                "action_config {",
-                "   config_name: 'c++-link-static-library'",
-                "   action_name: 'c++-link-static-library'",
-                "   tool {",
-                "       tool_path: 'DUMMY_TOOL'",
-                "   }",
-                "   implies: 'global_whole_archive_open'",
-                "   implies: 'runtime_root_flags'",
-                "   implies: 'input_param_flags'",
-                "   implies: 'global_whole_archive_close'",
-                "}",
-                "action_config {",
-                "   config_name: 'c++-link-alwayslink-static-library'",
-                "   action_name: 'c++-link-alwayslink-static-library'",
-                "   tool {",
-                "       tool_path: 'DUMMY_TOOL'",
-                "   }",
-                "   implies: 'global_whole_archive_open'",
-                "   implies: 'runtime_root_flags'",
-                "   implies: 'input_param_flags'",
-                "   implies: 'global_whole_archive_close'",
-                "}",
-                "action_config {",
-                "   config_name: 'c++-link-pic-static-library'",
-                "   action_name: 'c++-link-pic-static-library'",
-                "   tool {",
-                "       tool_path: 'DUMMY_TOOL'",
-                "   }",
-                "   implies: 'global_whole_archive_open'",
-                "   implies: 'runtime_root_flags'",
-                "   implies: 'input_param_flags'",
-                "   implies: 'global_whole_archive_close'",
-                "}",
-                "action_config {",
-                "   config_name: 'c++-link-alwayslink-pic-static-library'",
-                "   action_name: 'c++-link-alwayslink-pic-static-library'",
-                "   tool {",
-                "       tool_path: 'DUMMY_TOOL'",
-                "   }",
-                "   implies: 'global_whole_archive_open'",
-                "   implies: 'runtime_root_flags'",
-                "   implies: 'input_param_flags'",
-                "   implies: 'global_whole_archive_close'",
-                "}",
-                "feature {",
-                "   name: 'symbol_counts'",
-                "   flag_set {",
-                "       expand_if_all_available: 'symbol_counts_output'",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       flag_group {",
-                "           flag: '-Wl,--print-symbol-counts=%{symbol_counts_output}'",
-                "       }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'shared_flag'",
-                "   flag_set {",
-                "       action: 'c++-link-dynamic-library'",
-                "       flag_group {",
-                "           flag: '-shared'",
-                "       }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'linkstamps'",
-                "   flag_set {",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       expand_if_all_available: 'linkstamp_paths'",
-                "       flag_group {",
-                "           flag: '%{linkstamp_paths}'",
-                "       }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'output_execpath_flags'",
-                "   flag_set {",
-                "       expand_if_all_available: 'output_execpath'",
-                "       action: 'c++-link-dynamic-library'",
-                "       flag_group {",
-                "           flag: '-o'",
-                "           flag: '%{output_execpath}'",
-                "       }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'output_execpath_flags_executable'",
-                "   flag_set {",
-                "      expand_if_all_available: 'output_execpath'",
-                "      action: 'c++-link-executable'",
-                "      flag_group {",
-                "         flag: '-o'",
-                "      }",
-                "   }",
-                "   flag_set {",
-                "      expand_if_all_available: 'skip_mostly_static'",
-                "      expand_if_all_available: 'output_execpath'",
-                "      action: 'c++-link-executable'",
-                "      flag_group {",
-                "         flag: '/dev/null'",
-                "         flag: '-MMD'",
-                "         flag: '-MF'",
-                "      }",
-                "   }",
-                "   flag_set {",
-                "      expand_if_all_available: 'output_execpath'",
-                "      action: 'c++-link-executable'",
-                "      flag_group {",
-                "         flag: '%{output_execpath}'",
-                "      }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'global_whole_archive_open'",
-                "   flag_set {",
-                "      expand_if_all_available: 'global_whole_archive'",
-                "      action: 'c++-link-executable'",
-                "      action: 'c++-link-dynamic-library'",
-                "      action: 'c++-link-static-library'",
-                "      action: 'c++-link-alwayslink-static-library'",
-                "      action: 'c++-link-pic-static-library'",
-                "      action: 'c++-link-alwayslink-pic-static-library'",
-                "      flag_group {",
-                // TODO: Factor platform difference into respective linux and OSX crosstools.
-                String.format(
-                    "          flag:'%s'",
-                    platform == CppLinkPlatform.LINUX ? "-Wl,-whole-archive" : "-Wl,-all_load"),
-                "      }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'runtime_root_flags',",
-                "   flag_set {",
-                "       expand_if_all_available: 'runtime_root_flags'",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       action: 'c++-link-static-library'",
-                "       action: 'c++-link-alwayslink-static-library'",
-                "       action: 'c++-link-pic-static-library'",
-                "       action: 'c++-link-alwayslink-pic-static-library'",
-                "       flag_group {",
-                "           flag: '%{runtime_root_flags}'",
-                "       }",
-                "   }",
-                "   flag_set {",
-                "       expand_if_all_available: 'runtime_root_entries'",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       action: 'c++-link-static-library'",
-                "       action: 'c++-link-alwayslink-static-library'",
-                "       action: 'c++-link-pic-static-library'",
-                "       action: 'c++-link-alwayslink-pic-static-library'",
-                "       flag_group {",
-                "           flag: '%{runtime_root_entries}'",
-                "       }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'input_param_flags'",
-                "   flag_set {",
-                "       expand_if_all_available: 'libopts'",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       action: 'c++-link-static-library'",
-                "       action: 'c++-link-alwayslink-static-library'",
-                "       action: 'c++-link-pic-static-library'",
-                "       action: 'c++-link-alwayslink-pic-static-library'",
-                "       flag_group {",
-                "           flag: '%{libopts}'",
-                "       }",
-                "   }",
-                "   flag_set {",
-                "       expand_if_all_available: 'whole_archive_linker_params'",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       action: 'c++-link-static-library'",
-                "       action: 'c++-link-alwayslink-static-library'",
-                "       action: 'c++-link-pic-static-library'",
-                "       action: 'c++-link-alwayslink-pic-static-library'",
-                "       flag_group {",
-                platform == CppLinkPlatform.LINUX
-                    ? "          flag: '-Wl,-whole-archive'\n"
-                        + "          flag: '%{whole_archive_linker_params}'\n"
-                        + "          flag: '-Wl,-no-whole-archive'"
-                    : "          flag: '-Wl,-force_load,%{whole_archive_linker_params}'",
-                "       }",
-                "   }",
-                "   flag_set {",
-                "       expand_if_all_available: 'linker_input_params'",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       action: 'c++-link-static-library'",
-                "       action: 'c++-link-alwayslink-static-library'",
-                "       action: 'c++-link-pic-static-library'",
-                "       action: 'c++-link-alwayslink-pic-static-library'",
-                "       flag_group {",
-                "           flag: '%{linker_input_params}'",
-                "       }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'global_whole_archive_close'",
-                "   flag_set {",
-                "       expand_if_all_available: 'global_whole_archive'",
-                "       action: 'c++-link-executable'",
-                "       action: 'c++-link-dynamic-library'",
-                "       action: 'c++-link-static-library'",
-                "       action: 'c++-link-alwayslink-static-library'",
-                "       action: 'c++-link-pic-static-library'",
-                "       action: 'c++-link-alwayslink-pic-static-library'",
-                "       flag_group {",
-                // TODO: Factor platform difference into respective linux and OSX crosstools.
-                String.format(
-                    "           flag: '%s'",
-                    platform == CppLinkPlatform.LINUX ? "-Wl,-no-whole-archive" : ""),
-                "       }",
-                "   }",
-                "}",
-                "feature {",
-                "   name: 'force_pic_flags'",
-                "   flag_set {",
-                "       expand_if_all_available: 'force_pic'",
-                "       action: 'c++-link-executable'",
-                "       flag_group {",
-                "           flag: '-pie'",
-                "       }",
-                "   }",
-                "}"));
-  }
-}
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
index 13866e8..d3cbeaf 100644
--- 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
@@ -41,6 +41,7 @@
 import com.google.devtools.build.lib.util.Preconditions;
 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;
@@ -48,6 +49,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
+
 import javax.annotation.Nullable;
 
 /**
@@ -360,6 +362,11 @@
     return result;
   }
 
+  private CcToolchainFeatures.Variables linkBuildVariables() {
+    return new CcToolchainFeatures.Variables.Builder()
+        .addAllVariables(CppHelper.getToolchain(ruleContext).getBuildVariables()).build();
+  }
+  
   private void setupCompileBuildVariables(
       CppCompileActionBuilder builder,
       boolean usePic,
@@ -837,6 +844,7 @@
             .setLinkType(linkType)
             .setLinkStaticness(LinkStaticness.FULLY_STATIC)
             .setFeatureConfiguration(featureConfiguration)
+            .setBuildVariables(linkBuildVariables())
             .build();
     env.registerAction(maybePicAction);
     result.addStaticLibrary(maybePicAction.getOutputLibrary());
@@ -861,6 +869,7 @@
               .setLinkType(picLinkType)
               .setLinkStaticness(LinkStaticness.FULLY_STATIC)
               .setFeatureConfiguration(featureConfiguration)
+              .setBuildVariables(linkBuildVariables())
               .build();
       env.registerAction(picAction);
       result.addPicStaticLibrary(picAction.getOutputLibrary());
@@ -904,7 +913,8 @@
             .setRuntimeInputs(
                 CppHelper.getToolchain(ruleContext).getDynamicRuntimeLinkMiddleman(),
                 CppHelper.getToolchain(ruleContext).getDynamicRuntimeLinkInputs())
-            .setFeatureConfiguration(featureConfiguration);
+            .setFeatureConfiguration(featureConfiguration)
+            .setBuildVariables(linkBuildVariables());
 
     if (!ccOutputs.getLtoBitcodeFiles().isEmpty()
         && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java
index c5cb301..96b5a3b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java
@@ -17,6 +17,7 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Predicates;
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -31,18 +32,23 @@
 import com.google.devtools.build.lib.collect.CollectionUtils;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables;
 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.util.Pair;
 import com.google.devtools.build.lib.util.Preconditions;
 import com.google.devtools.build.lib.util.ShellEscaper;
 import com.google.devtools.build.lib.vfs.PathFragment;
+
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+
 import javax.annotation.Nullable;
 
 /**
@@ -60,6 +66,7 @@
   @Nullable private final FeatureConfiguration featureConfiguration;
   @Nullable private final Artifact output;
   @Nullable private final Artifact interfaceOutput;
+  @Nullable private final Artifact symbolCountsOutput;
   private final ImmutableList<Artifact> buildInfoHeaderArtifacts;
   private final Iterable<? extends LinkerInput> linkerInputs;
   private final Iterable<? extends LinkerInput> runtimeInputs;
@@ -73,8 +80,9 @@
   @Nullable private final PathFragment runtimeSolibDir;
   private final boolean nativeDeps;
   private final boolean useTestOnlyFlags;
-  private final List<String> noWholeArchiveFlags;
+  private final boolean needWholeArchive;
 
+  @Nullable private final Iterable<LTOBackendArtifacts> allLTOArtifacts;
   @Nullable private final Artifact paramFile;
   @Nullable private final Artifact interfaceSoBuilder;
 
@@ -84,6 +92,7 @@
       ActionOwner owner,
       Artifact output,
       @Nullable Artifact interfaceOutput,
+      @Nullable Artifact symbolCountsOutput,
       ImmutableList<Artifact> buildInfoHeaderArtifacts,
       Iterable<? extends LinkerInput> linkerInputs,
       Iterable<? extends LinkerInput> runtimeInputs,
@@ -98,11 +107,33 @@
       boolean nativeDeps,
       boolean useTestOnlyFlags,
       boolean needWholeArchive,
+      @Nullable Iterable<LTOBackendArtifacts> allLTOArtifacts,
       @Nullable Artifact paramFile,
       Artifact interfaceSoBuilder,
-      List<String> noWholeArchiveFlags,
       CcToolchainFeatures.Variables variables,
       @Nullable FeatureConfiguration featureConfiguration) {
+    Preconditions.checkArgument(linkTargetType != LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
+        "you can't link an interface dynamic library directly");
+    if (linkTargetType != LinkTargetType.DYNAMIC_LIBRARY) {
+      Preconditions.checkArgument(interfaceOutput == null,
+          "interface output may only be non-null for dynamic library links");
+    }
+    if (linkTargetType.isStaticLibraryLink()) {
+      Preconditions.checkArgument(linkstamps.isEmpty(),
+          "linkstamps may only be present on dynamic library or executable links");
+      Preconditions.checkArgument(linkStaticness == LinkStaticness.FULLY_STATIC,
+          "static library link must be static");
+      Preconditions.checkArgument(buildInfoHeaderArtifacts.isEmpty(),
+          "build info headers may only be present on dynamic library or executable links");
+      Preconditions.checkArgument(symbolCountsOutput == null,
+          "the symbol counts output must be null for static links");
+      Preconditions.checkArgument(runtimeSolibDir == null,
+          "the runtime solib directory must be null for static links");
+      Preconditions.checkArgument(!nativeDeps,
+          "the native deps flag must be false for static links");
+      Preconditions.checkArgument(!needWholeArchive,
+          "the need whole archive flag must be false for static links");
+    }
 
     this.actionName = actionName;
     this.configuration = Preconditions.checkNotNull(configuration);
@@ -116,6 +147,7 @@
       Preconditions.checkNotNull(this.output);
     }
 
+    this.symbolCountsOutput = symbolCountsOutput;
     this.buildInfoHeaderArtifacts = Preconditions.checkNotNull(buildInfoHeaderArtifacts);
     this.linkerInputs = Preconditions.checkNotNull(linkerInputs);
     this.runtimeInputs = Preconditions.checkNotNull(runtimeInputs);
@@ -132,15 +164,16 @@
     this.runtimeSolibDir = runtimeSolibDir;
     this.nativeDeps = nativeDeps;
     this.useTestOnlyFlags = useTestOnlyFlags;
+    this.needWholeArchive = needWholeArchive;
+    this.allLTOArtifacts = allLTOArtifacts;
     this.paramFile = paramFile;
-    this.noWholeArchiveFlags = noWholeArchiveFlags;
 
     // For now, silently ignore interfaceSoBuilder if we don't build an interface dynamic library.
     this.interfaceSoBuilder =
         ((linkTargetType == LinkTargetType.DYNAMIC_LIBRARY) && (interfaceOutput != null))
-            ? Preconditions.checkNotNull(
-                interfaceSoBuilder, "cannot build interface dynamic library without builder")
-            : null;
+        ? Preconditions.checkNotNull(interfaceSoBuilder,
+            "cannot build interface dynamic library without builder")
+        : null;
   }
 
   /**
@@ -153,6 +186,15 @@
     return interfaceOutput;
   }
 
+  /**
+   * Returns an artifact containing the number of symbols used per object file passed to the linker.
+   * This is currently a gold only feature, and is only produced for executables. If another target
+   * is being linked, or if symbol counts output is disabled, this will be null.
+   */
+  @Nullable public Artifact getSymbolCountsOutput() {
+    return symbolCountsOutput;
+  }
+
   @Nullable
   public Artifact getParamFile() {
     return paramFile;
@@ -236,12 +278,6 @@
     return useTestOnlyFlags;
   }
 
-  /** Returns the build variables used to template the crosstool for this linker invocation. */
-  @VisibleForTesting
-  public Variables getBuildVariables() {
-    return this.variables;
-  }
-
   /**
    * Splits the link command-line into a part to be written to a parameter file, and the remaining
    * actual command line to be executed (which references the parameter file). Should only be used
@@ -335,110 +371,76 @@
       }
     }
   }
-  
-  private void addToolchainFlags(List<String> argv) {
-    boolean fullyStatic = (linkStaticness == LinkStaticness.FULLY_STATIC);
-    boolean mostlyStatic = (linkStaticness == LinkStaticness.MOSTLY_STATIC);
-    boolean sharedLinkopts =
-        linkTargetType == LinkTargetType.DYNAMIC_LIBRARY
-            || linkopts.contains("-shared")
-            || cppConfiguration.getLinkOptions().contains("-shared");
-
-    /*
-     * For backwards compatibility, linkopts come _after_ inputFiles.
-     * This is needed to allow linkopts to contain libraries and
-     * positional library-related options such as
-     *    -Wl,--begin-group -lfoo -lbar -Wl,--end-group
-     * or
-     *    -Wl,--as-needed -lfoo -Wl,--no-as-needed
-     *
-     * As for the relative order of the three different flavours of linkopts
-     * (global defaults, per-target linkopts, and command-line linkopts),
-     * we have no idea what the right order should be, or if anyone cares.
-     */
-    argv.addAll(linkopts);
-    // Extra toolchain link options based on the output's link staticness.
-    if (fullyStatic) {
-      argv.addAll(cppConfiguration.getFullyStaticLinkOptions(features, sharedLinkopts));
-    } else if (mostlyStatic) {
-      argv.addAll(cppConfiguration.getMostlyStaticLinkOptions(features, sharedLinkopts));
-    } else {
-      argv.addAll(cppConfiguration.getDynamicLinkOptions(features, sharedLinkopts));
-    }
-
-    // Extra test-specific link options.
-    if (useTestOnlyFlags) {
-      argv.addAll(cppConfiguration.getTestOnlyLinkOptions());
-    }
-
-    argv.addAll(cppConfiguration.getLinkOptions());
-
-    // -pie is not compatible with shared and should be
-    // removed when the latter is part of the link command. Should we need to further
-    // distinguish between shared libraries and executables, we could add additional
-    // command line / CROSSTOOL flags that distinguish them. But as long as this is
-    // the only relevant use case we're just special-casing it here.
-    if (linkTargetType == LinkTargetType.DYNAMIC_LIBRARY) {
-      Iterables.removeIf(argv, Predicates.equalTo("-pie"));
-    }
-
-    // Fission mode: debug info is in .dwo files instead of .o files. Inform the linker of this.
-    if (!linkTargetType.isStaticLibraryLink() && cppConfiguration.useFission()) {
-      argv.add("-Wl,--gdb-index");
-    }
-  }
 
   /**
-   * Returns a raw link command for the given link invocation, including both command and arguments
-   * (argv). After any further usage-specific processing, this can be passed to {@link
-   * #finalizeWithLinkstampCommands} to give the final command line.
+   * Returns a raw link command for the given link invocation, including both command and
+   * arguments (argv). After any further usage-specific processing, this can be passed to
+   * {@link #finalizeWithLinkstampCommands} to give the final command line.
    *
    * @return raw link command line.
    */
   public List<String> getRawLinkArgv() {
     List<String> argv = new ArrayList<>();
 
-    switch (linkTargetType) {
-      case EXECUTABLE:
-        argv.add(cppConfiguration.getCppExecutable().getPathString());
-        argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
-        argv.addAll(noWholeArchiveFlags);
-        addToolchainFlags(argv);
-        break;
+    // We create the command line from the feature configuration.  If no configuration is present,
+    // we use hard-coded flags.
+    if (featureConfiguration.actionIsConfigured(actionName)) {
+      argv.add(featureConfiguration
+            .getToolForAction(actionName)
+            .getToolPath(cppConfiguration.getCrosstoolTopPathFragment())
+            .getPathString());
+      argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
+    } else {
+      // TODO(b/28928350): In order to simplify the extraction of this logic into the linux
+      // crosstool, this switch statement should be reframed as a group of action_configs and
+      // features.  Until they can be migrated into the linux crosstool, those features should
+      // be added to CppConfiguration.addLegacyFeatures().
+      switch (linkTargetType) {
+        case EXECUTABLE:
+          addCppArgv(argv);
+          break;
 
-      case DYNAMIC_LIBRARY:
-        if (interfaceOutput != null) {
-          argv.add(configuration.getShExecutable().getPathString());
-          argv.add("-c");
-          argv.add(
-              "build_iface_so=\"$0\"; impl=\"$1\"; iface=\"$2\"; cmd=\"$3\"; shift 3; "
-                  + "\"$cmd\" \"$@\" && \"$build_iface_so\" \"$impl\" \"$iface\"");
-          argv.add(interfaceSoBuilder.getExecPathString());
+        case DYNAMIC_LIBRARY:
+          if (interfaceOutput != null) {
+            argv.add(configuration.getShExecutable().getPathString());
+            argv.add("-c");
+            argv.add(
+                "build_iface_so=\"$0\"; impl=\"$1\"; iface=\"$2\"; cmd=\"$3\"; shift 3; "
+                    + "\"$cmd\" \"$@\" && \"$build_iface_so\" \"$impl\" \"$iface\"");
+            argv.add(interfaceSoBuilder.getExecPathString());
+            argv.add(output.getExecPathString());
+            argv.add(interfaceOutput.getExecPathString());
+          }
+          addCppArgv(argv);
+          // -pie is not compatible with -shared and should be
+          // removed when the latter is part of the link command. Should we need to further
+          // distinguish between shared libraries and executables, we could add additional
+          // command line / CROSSTOOL flags that distinguish them. But as long as this is
+          // the only relevant use case we're just special-casing it here.
+          Iterables.removeIf(argv, Predicates.equalTo("-pie"));
+          break;
+
+        case STATIC_LIBRARY:
+        case PIC_STATIC_LIBRARY:
+        case ALWAYS_LINK_STATIC_LIBRARY:
+        case ALWAYS_LINK_PIC_STATIC_LIBRARY:
+          // The static library link command follows this template:
+          // ar <cmd> <output_archive> <input_files...>
+          argv.add(cppConfiguration.getArExecutable().getPathString());
+          argv.addAll(
+              cppConfiguration.getArFlags(cppConfiguration.archiveType() == Link.ArchiveType.THIN));
           argv.add(output.getExecPathString());
-          argv.add(interfaceOutput.getExecPathString());
-        }
-        argv.add(cppConfiguration.getCppExecutable().getPathString());
-        argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
-        argv.addAll(noWholeArchiveFlags);
-        addToolchainFlags(argv);
-        break;
+          addInputFileLinkOptions(argv, /*needWholeArchive=*/ false);
+          break;
 
-      case STATIC_LIBRARY:
-      case PIC_STATIC_LIBRARY:
-      case ALWAYS_LINK_STATIC_LIBRARY:
-      case ALWAYS_LINK_PIC_STATIC_LIBRARY:
-        // The static library link command follows this template:
-        // ar <cmd> <output_archive> <input_files...>
-        argv.add(cppConfiguration.getArExecutable().getPathString());
-        argv.addAll(
-            cppConfiguration.getArFlags(cppConfiguration.archiveType() == Link.ArchiveType.THIN));
-        argv.add(output.getExecPathString());
-        argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
-        argv.addAll(noWholeArchiveFlags);
-        break;
+        default:
+          throw new IllegalArgumentException();
+      }
+    }
 
-      default:
-        throw new IllegalArgumentException();
+    // Fission mode: debug info is in .dwo files instead of .o files. Inform the linker of this.
+    if (!linkTargetType.isStaticLibraryLink() && cppConfiguration.useFission()) {
+      argv.add("-Wl,--gdb-index");
     }
 
     return argv;
@@ -535,23 +537,21 @@
       return ImmutableList.copyOf(batchCommand);
     }
   }
-  
-  private boolean isSharedNativeLibrary() {
-    return nativeDeps && cppConfiguration.shareNativeDeps();
-  }
 
   /**
-   * Computes, for each C++ source file in {@link #getLinkstamps}, the command necessary to compile
+   * Computes, for each C++ source file in
+   * {@link #getLinkstamps}, the command necessary to compile
    * that file such that the output is correctly fed into the link command.
    *
-   * <p>As these options (as well as all others) are taken into account when computing the action
-   * key, they do not directly contain volatile build information to avoid unnecessary relinking.
-   * Instead this information is passed as an additional header generated by {@link
-   * com.google.devtools.build.lib.rules.cpp.WriteBuildInfoHeaderAction}.
+   * <p>As these options (as well as all others) are taken into account when
+   * computing the action key, they do not directly contain volatile build
+   * information to avoid unnecessary relinking. Instead this information is
+   * passed as an additional header generated by
+   * {@link com.google.devtools.build.lib.rules.cpp.WriteBuildInfoHeaderAction}.
    *
    * @param outputPrefix prefix to add before the linkstamp outputs' exec paths
-   * @return a list of shell-escaped compiler commmands, one for each entry in {@link
-   *     #getLinkstamps}
+   * @return a list of shell-escaped compiler commmands, one for each entry
+   *         in {@link #getLinkstamps}
    */
   public List<String> getLinkstampCompileCommands(String outputPrefix) {
     if (linkstamps.isEmpty()) {
@@ -626,6 +626,369 @@
   }
 
   /**
+   * Determine the arguments to pass to the C++ compiler when linking.
+   * Add them to the {@code argv} parameter.
+   */
+  private void addCppArgv(List<String> argv) {
+    argv.add(cppConfiguration.getCppExecutable().getPathString());
+
+    // When using gold to link an executable, output the number of used and unused symbols.
+    if (symbolCountsOutput != null) {
+      argv.add("-Wl,--print-symbol-counts=" + symbolCountsOutput.getExecPathString());
+    }
+
+    if (linkTargetType == LinkTargetType.DYNAMIC_LIBRARY) {
+      argv.add("-shared");
+    }
+
+    // Add the outputs of any associated linkstamp compilations.
+    for (Artifact linkstampOutput : linkstamps.values()) {
+      argv.add(linkstampOutput.getExecPathString());
+    }
+
+    boolean fullyStatic = (linkStaticness == LinkStaticness.FULLY_STATIC);
+    boolean mostlyStatic = (linkStaticness == LinkStaticness.MOSTLY_STATIC);
+    boolean sharedLinkopts =
+        linkTargetType == LinkTargetType.DYNAMIC_LIBRARY
+        || linkopts.contains("-shared")
+        || cppConfiguration.getLinkOptions().contains("-shared");
+
+    if (output != null) {
+      argv.add("-o");
+      String execpath = output.getExecPathString();
+      if (mostlyStatic
+          && linkTargetType == LinkTargetType.EXECUTABLE
+          && cppConfiguration.skipStaticOutputs()) {
+        // Linked binary goes to /dev/null; bogus dependency info in its place.
+        Collections.addAll(argv, "/dev/null", "-MMD", "-MF", execpath);
+      } else {
+        argv.add(execpath);
+      }
+    }
+
+    addInputFileLinkOptions(argv, needWholeArchive);
+
+    /*
+     * For backwards compatibility, linkopts come _after_ inputFiles.
+     * This is needed to allow linkopts to contain libraries and
+     * positional library-related options such as
+     *    -Wl,--begin-group -lfoo -lbar -Wl,--end-group
+     * or
+     *    -Wl,--as-needed -lfoo -Wl,--no-as-needed
+     *
+     * As for the relative order of the three different flavours of linkopts
+     * (global defaults, per-target linkopts, and command-line linkopts),
+     * we have no idea what the right order should be, or if anyone cares.
+     */
+    argv.addAll(linkopts);
+
+    // Extra toolchain link options based on the output's link staticness.
+    if (fullyStatic) {
+      argv.addAll(cppConfiguration.getFullyStaticLinkOptions(features, sharedLinkopts));
+    } else if (mostlyStatic) {
+      argv.addAll(cppConfiguration.getMostlyStaticLinkOptions(features, sharedLinkopts));
+    } else {
+      argv.addAll(cppConfiguration.getDynamicLinkOptions(features, sharedLinkopts));
+    }
+
+    // Extra test-specific link options.
+    if (useTestOnlyFlags) {
+      argv.addAll(cppConfiguration.getTestOnlyLinkOptions());
+    }
+
+    if (linkTargetType == LinkTargetType.EXECUTABLE && cppConfiguration.forcePic()) {
+      argv.add("-pie");
+    }
+
+    argv.addAll(cppConfiguration.getLinkOptions());
+    // The feature config can be null for tests.
+    if (featureConfiguration != null) {
+      argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
+    }
+  }
+
+  private static boolean isDynamicLibrary(LinkerInput linkInput) {
+    Artifact libraryArtifact = linkInput.getArtifact();
+    String name = libraryArtifact.getFilename();
+    return Link.SHARED_LIBRARY_FILETYPES.matches(name) && name.startsWith("lib");
+  }
+
+  private boolean isSharedNativeLibrary() {
+    return nativeDeps && cppConfiguration.shareNativeDeps();
+  }
+
+  /**
+   * When linking a shared library fully or mostly static then we need to link in
+   * *all* dependent files, not just what the shared library needs for its own
+   * code. This is done by wrapping all objects/libraries with
+   * -Wl,-whole-archive and -Wl,-no-whole-archive. For this case the
+   * globalNeedWholeArchive parameter must be set to true.  Otherwise only
+   * library objects (.lo) need to be wrapped with -Wl,-whole-archive and
+   * -Wl,-no-whole-archive.
+   */
+  private void addInputFileLinkOptions(List<String> argv, boolean globalNeedWholeArchive) {
+    // The Apple ld doesn't support -whole-archive/-no-whole-archive. It
+    // does have -all_load/-noall_load, but -all_load is a global setting
+    // that affects all subsequent files, and -noall_load is simply ignored.
+    // TODO(bazel-team): Not sure what the implications of this are, other than
+    // bloated binaries.
+    boolean macosx = cppConfiguration.getTargetLibc().equals("macosx");
+    if (globalNeedWholeArchive) {
+      argv.add(macosx ? "-Wl,-all_load" : "-Wl,-whole-archive");
+    }
+
+    // Used to collect -L and -Wl,-rpath options, ensuring that each used only once.
+    Set<String> libOpts = new LinkedHashSet<>();
+
+    // List of command line parameters to link input files (either directly or using -l).
+    List<String> linkerInputs = new ArrayList<>();
+
+    // List of command line parameters that need to be placed *outside* of
+    // --whole-archive ... --no-whole-archive.
+    List<String> noWholeArchiveInputs = new ArrayList<>();
+
+    PathFragment solibDir = configuration.getBinDirectory().getExecPath()
+        .getRelative(cppConfiguration.getSolibDirectory());
+    String runtimeSolibName = runtimeSolibDir != null ? runtimeSolibDir.getBaseName() : null;
+    boolean runtimeRpath = runtimeSolibDir != null
+        && (linkTargetType == LinkTargetType.DYNAMIC_LIBRARY
+        || (linkTargetType == LinkTargetType.EXECUTABLE
+        && linkStaticness == LinkStaticness.DYNAMIC));
+
+    String rpathRoot = null;
+    List<String> runtimeRpathEntries = new ArrayList<>();
+
+    if (output != null) {
+      String origin =
+          useTestOnlyFlags && cppConfiguration.supportsExecOrigin() ? "$EXEC_ORIGIN/" : "$ORIGIN/";
+      if (runtimeRpath) {
+        runtimeRpathEntries.add("-Wl,-rpath," + origin + runtimeSolibName + "/");
+      }
+
+      // Calculate the correct relative value for the "-rpath" link option (which sets
+      // the search path for finding shared libraries).
+      if (isSharedNativeLibrary()) {
+        // For shared native libraries, special symlinking is applied to ensure C++
+        // runtimes are available under $ORIGIN/_solib_[arch]. So we set the RPATH to find
+        // them.
+        //
+        // Note that we have to do this because $ORIGIN points to different paths for
+        // different targets. In other words, blaze-bin/d1/d2/d3/a_shareddeps.so and
+        // blaze-bin/d4/b_shareddeps.so have different path depths. The first could
+        // reference a standard blaze-bin/_solib_[arch] via $ORIGIN/../../../_solib[arch],
+        // and the second could use $ORIGIN/../_solib_[arch]. But since this is a shared
+        // artifact, both are symlinks to the same place, so
+        // there's no *one* RPATH setting that fits all targets involved in the sharing.
+        rpathRoot = "-Wl,-rpath," + origin + ":"
+            + origin + cppConfiguration.getSolibDirectory() + "/";
+        if (runtimeRpath) {
+          runtimeRpathEntries.add("-Wl,-rpath," + origin + "../" + runtimeSolibName + "/");
+        }
+      } else {
+        // For all other links, calculate the relative path from the output file to _solib_[arch]
+        // (the directory where all shared libraries are stored, which resides under the blaze-bin
+        // directory. In other words, given blaze-bin/my/package/binary, rpathRoot would be
+        // "../../_solib_[arch]".
+        if (runtimeRpath) {
+          runtimeRpathEntries.add("-Wl,-rpath," + origin
+              + Strings.repeat("../", output.getRootRelativePath().segmentCount() - 1)
+              + runtimeSolibName + "/");
+        }
+
+        rpathRoot = "-Wl,-rpath,"
+            + origin + Strings.repeat("../", output.getRootRelativePath().segmentCount() - 1)
+            + cppConfiguration.getSolibDirectory() + "/";
+
+        if (nativeDeps) {
+          // We also retain the $ORIGIN/ path to solibs that are in _solib_<arch>, as opposed to
+          // the package directory)
+          if (runtimeRpath) {
+            runtimeRpathEntries.add("-Wl,-rpath," + origin + "../" + runtimeSolibName + "/");
+          }
+          rpathRoot += ":" + origin;
+        }
+      }
+    }
+
+    boolean includeSolibDir = false;
+
+
+    Map<Artifact, Artifact> ltoMap = null;
+    if (allLTOArtifacts != null) {
+      // TODO(bazel-team): The LTO final link can only work if there are individual .o files on the
+      // command line. Rather than crashing, this should issue a nice error. We will get this by
+      // 1) moving supports_start_end_lib to a toolchain feature
+      // 2) having thin_lto require start_end_lib
+      // As a bonus, we can rephrase --nostart_end_lib as --features=-start_end_lib and get rid
+      // of a command line option.
+
+      Preconditions.checkState(cppConfiguration.useStartEndLib());
+      ltoMap = new HashMap<>();
+      for (LTOBackendArtifacts l : allLTOArtifacts) {
+        ltoMap.put(l.getBitcodeFile(), l.getObjectFile());
+      }
+    }
+
+    for (LinkerInput input : getLinkerInputs()) {
+      if (isDynamicLibrary(input)) {
+        PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
+        Preconditions.checkState(
+            libDir.startsWith(solibDir),
+            "Artifact '%s' is not under directory '%s'.", input.getArtifact(), solibDir);
+        if (libDir.equals(solibDir)) {
+          includeSolibDir = true;
+        }
+        addDynamicInputLinkOptions(input, linkerInputs, libOpts, solibDir, rpathRoot);
+      } else {
+        addStaticInputLinkOptions(input, linkerInputs, ltoMap);
+      }
+    }
+
+    boolean includeRuntimeSolibDir = false;
+
+    for (LinkerInput input : runtimeInputs) {
+      List<String> optionsList = globalNeedWholeArchive
+          ? noWholeArchiveInputs
+          : linkerInputs;
+
+      if (isDynamicLibrary(input)) {
+        PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
+        Preconditions.checkState(runtimeSolibDir != null && libDir.equals(runtimeSolibDir),
+            "Artifact '%s' is not under directory '%s'.", input.getArtifact(), solibDir);
+        includeRuntimeSolibDir = true;
+        addDynamicInputLinkOptions(input, optionsList, libOpts, solibDir, rpathRoot);
+      } else {
+        addStaticInputLinkOptions(input, optionsList, ltoMap);
+      }
+    }
+
+    // rpath ordering matters for performance; first add the one where most libraries are found.
+    if (includeSolibDir && rpathRoot != null) {
+      argv.add(rpathRoot);
+    }
+    if (includeRuntimeSolibDir) {
+      argv.addAll(runtimeRpathEntries);
+    }
+    argv.addAll(libOpts);
+
+    // Need to wrap static libraries with whole-archive option
+    for (String option : linkerInputs) {
+      if (!globalNeedWholeArchive && Link.LINK_LIBRARY_FILETYPES.matches(option)) {
+        if (macosx) {
+          argv.add("-Wl,-force_load," + option);
+        } else {
+          argv.add("-Wl,-whole-archive");
+          argv.add(option);
+          argv.add("-Wl,-no-whole-archive");
+        }
+      } else {
+        argv.add(option);
+      }
+    }
+
+    if (globalNeedWholeArchive) {
+      argv.add(macosx ? "-Wl,-noall_load" : "-Wl,-no-whole-archive");
+      argv.addAll(noWholeArchiveInputs);
+    }
+
+    if (ltoMap != null) {
+      Preconditions.checkState(
+          ltoMap.size() == 0, "Still have LTO objects left: %s, command-line: %s", ltoMap, argv);
+    }
+  }
+
+  /**
+   * Adds command-line options for a dynamic library input file into
+   * options and libOpts.
+   */
+  private void addDynamicInputLinkOptions(LinkerInput input, List<String> options,
+      Set<String> libOpts, PathFragment solibDir, String rpathRoot) {
+    Preconditions.checkState(isDynamicLibrary(input));
+    Preconditions.checkState(
+        !Link.useStartEndLib(input, cppConfiguration.archiveType()));
+
+    Artifact inputArtifact = input.getArtifact();
+    PathFragment libDir = inputArtifact.getExecPath().getParentDirectory();
+    if (rpathRoot != null
+        && !libDir.equals(solibDir)
+        && (runtimeSolibDir == null || !runtimeSolibDir.equals(libDir))) {
+      String dotdots = "";
+      PathFragment commonParent = solibDir;
+      while (!libDir.startsWith(commonParent)) {
+        dotdots += "../";
+        commonParent = commonParent.getParentDirectory();
+      }
+
+      libOpts.add(rpathRoot + dotdots + libDir.relativeTo(commonParent).getPathString());
+    }
+
+    libOpts.add("-L" + inputArtifact.getExecPath().getParentDirectory().getPathString());
+
+    String name = inputArtifact.getFilename();
+    if (CppFileTypes.SHARED_LIBRARY.matches(name)) {
+      String libName = name.replaceAll("(^lib|\\.(so|dylib)$)", "");
+      options.add("-l" + libName);
+    } else {
+      // Interface shared objects have a non-standard extension
+      // that the linker won't be able to find.  So use the
+      // filename directly rather than a -l option.  Since the
+      // library has an SONAME attribute, this will work fine.
+      options.add(inputArtifact.getExecPathString());
+    }
+  }
+
+  /**
+   * Adds command-line options for a static library or non-library input
+   * into options.
+   *
+   * @param ltoMap is a mutable list of exec paths that should be on the command-line, which
+   *    must be supplied for LTO final links.
+   */
+  private void addStaticInputLinkOptions(
+      LinkerInput input, List<String> options, @Nullable Map<Artifact, Artifact> ltoMap) {
+    Preconditions.checkState(!isDynamicLibrary(input));
+
+    // start-lib/end-lib library: adds its input object files.
+    if (Link.useStartEndLib(input, cppConfiguration.archiveType())) {
+      Iterable<Artifact> archiveMembers = input.getObjectFiles();
+      if (!Iterables.isEmpty(archiveMembers)) {
+        options.add("-Wl,--start-lib");
+        for (Artifact member : archiveMembers) {
+          if (ltoMap != null) {
+            Artifact backend = ltoMap.remove(member);
+
+            if (backend != null) {
+              // If the backend artifact is missing, we can't print a warning because this may
+              // happen normally, due libraries that list .o files explicitly, or generate .o
+              // files from assembler.
+              member = backend;
+            }
+          }
+
+          options.add(member.getExecPathString());
+        }
+        options.add("-Wl,--end-lib");
+      }
+    } else {
+      // For anything else, add the input directly.
+      Artifact inputArtifact = input.getArtifact();
+
+      if (ltoMap != null) {
+        Artifact ltoArtifact = ltoMap.remove(inputArtifact);
+        if (ltoArtifact != null) {
+          inputArtifact = ltoArtifact;
+        }
+      }
+
+      if (input.isFake()) {
+        options.add(Link.FAKE_OBJECT_PREFIX + inputArtifact.getExecPathString());
+      } else {
+        options.add(inputArtifact.getExecPathString());
+      }
+    }
+  }
+
+  /**
    * A builder for a {@link LinkCommandLine}.
    */
   public static final class Builder {
@@ -650,8 +1013,10 @@
     private final ActionOwner owner;
     @Nullable private final RuleContext ruleContext;
 
+    private String actionName;
     @Nullable private Artifact output;
     @Nullable private Artifact interfaceOutput;
+    @Nullable private Artifact symbolCountsOutput;
     private ImmutableList<Artifact> buildInfoHeaderArtifacts = ImmutableList.of();
     private Iterable<? extends LinkerInput> linkerInputs = ImmutableList.of();
     private Iterable<? extends LinkerInput> runtimeInputs = ImmutableList.of();
@@ -665,18 +1030,17 @@
     private boolean nativeDeps;
     private boolean useTestOnlyFlags;
     private boolean needWholeArchive;
+    @Nullable private Iterable<LTOBackendArtifacts> allLTOBackendArtifacts;
     @Nullable private Artifact paramFile;
     @Nullable private Artifact interfaceSoBuilder;
     @Nullable private CcToolchainProvider toolchain;
-    private Variables variables;
     private FeatureConfiguration featureConfiguration;
-    private List<String> noWholeArchiveFlags = ImmutableList.of();
 
     // This interface is needed to support tests that don't create a
     // ruleContext, in which case the configuration and action owner
     // cannot be accessed off of the give ruleContext.
-    public Builder(
-        BuildConfiguration configuration, ActionOwner owner, @Nullable RuleContext ruleContext) {
+    public Builder(BuildConfiguration configuration, ActionOwner owner,
+        @Nullable RuleContext ruleContext) {
       this.configuration = configuration;
       this.owner = owner;
       this.ruleContext = ruleContext;
@@ -687,16 +1051,6 @@
     }
 
     public LinkCommandLine build() {
-      
-      if (linkTargetType.isStaticLibraryLink()) {
-        Preconditions.checkArgument(
-            linkstamps.isEmpty(),
-            "linkstamps may only be present on dynamic library or executable links");
-        Preconditions.checkArgument(
-            buildInfoHeaderArtifacts.isEmpty(),
-            "build info headers may only be present on dynamic library or executable links");
-      }
-
       ImmutableList<String> actualLinkstampCompileOptions;
       if (linkstampCompileOptions.isEmpty()) {
         actualLinkstampCompileOptions = DEFAULT_LINKSTAMP_OPTIONS;
@@ -704,7 +1058,7 @@
         actualLinkstampCompileOptions = ImmutableList.copyOf(
             Iterables.concat(DEFAULT_LINKSTAMP_OPTIONS, linkstampCompileOptions));
       }
-
+      CcToolchainFeatures.Variables variables = null;
       // The ruleContext can be null for some tests.
       if (ruleContext != null) {
         if (featureConfiguration == null) {
@@ -716,20 +1070,18 @@
             featureConfiguration = CcCommon.configureFeatures(ruleContext);
           }
         }
+        CcToolchainFeatures.Variables.Builder buildVariables =
+            new CcToolchainFeatures.Variables.Builder();
+        CppHelper.getFdoSupport(ruleContext).getLinkOptions(featureConfiguration, buildVariables);
+        variables = buildVariables.build();
       }
-      
-      if (variables == null) {
-        variables = Variables.EMPTY;
-      }
-
-      String actionName = linkTargetType.getActionName();
-
       return new LinkCommandLine(
           actionName,
           configuration,
           owner,
           output,
           interfaceOutput,
+          symbolCountsOutput,
           buildInfoHeaderArtifacts,
           linkerInputs,
           runtimeInputs,
@@ -744,14 +1096,22 @@
           nativeDeps,
           useTestOnlyFlags,
           needWholeArchive,
+          allLTOBackendArtifacts,
           paramFile,
           interfaceSoBuilder,
-          noWholeArchiveFlags,
           variables,
           featureConfiguration);
     }
 
     /**
+     * Sets the name of the action for the purposes of querying the crosstool.
+     */
+    public Builder setActionName(String actionName) {
+      this.actionName = actionName;
+      return this;
+    }
+
+    /**
      * Sets the toolchain to use for link flags. If this is not called, the toolchain
      * is retrieved from the rule.
      */
@@ -814,9 +1174,19 @@
     }
 
     /**
+     * Sets an additional output artifact that contains symbol counts. The {@link #build} method
+     * throws an exception if this is non-null for a static link (see
+     * {@link LinkTargetType#isStaticLibraryLink}).
+     */
+    public Builder setSymbolCountsOutput(Artifact symbolCountsOutput) {
+      this.symbolCountsOutput = symbolCountsOutput;
+      return this;
+    }
+
+    /**
      * Sets the linker options. These are passed to the linker in addition to the other linker
-     * options like linker inputs, symbol count options, etc. The {@link #build} method throws an
-     * exception if the linker options are non-empty for a static link (see {@link
+     * options like linker inputs, symbol count options, etc. The {@link #build} method
+     * throws an exception if the linker options are non-empty for a static link (see {@link
      * LinkTargetType#isStaticLibraryLink}).
      */
     public Builder setLinkopts(ImmutableList<String> linkopts) {
@@ -883,6 +1253,16 @@
     }
 
     /**
+     * Sets the directory of the dynamic runtime libraries, which is added to the rpath. The {@link
+     * #build} method throws an exception if the runtime dir is non-null for a static link (see
+     * {@link LinkTargetType#isStaticLibraryLink}).
+     */
+    public Builder setRuntimeSolibDir(PathFragment runtimeSolibDir) {
+      this.runtimeSolibDir = runtimeSolibDir;
+      return this;
+    }
+
+    /**
      * Whether the resulting library is intended to be used as a native library from another
      * programming language. This influences the rpath. The {@link #build} method throws an
      * exception if this is true for a static link (see {@link LinkTargetType#isStaticLibraryLink}).
@@ -901,28 +1281,18 @@
       return this;
     }
 
+    public Builder setNeedWholeArchive(boolean needWholeArchive) {
+      this.needWholeArchive = needWholeArchive;
+      return this;
+    }
+
     public Builder setParamFile(Artifact paramFile) {
       this.paramFile = paramFile;
       return this;
     }
-    
-    public Builder setBuildVariables(Variables variables) {
-      this.variables = variables;
-      return this;
-    }
 
-    public Builder setRuntimeSolibDir(PathFragment runtimeSolibDir) {
-      this.runtimeSolibDir = runtimeSolibDir;
-      return this;
-    }
-
-    /**
-     * Set flags that should not be in a --whole_archive block.
-     *
-     * <p>TODO(b/30228443): Refactor into action_configs.
-     */
-    public Builder setNoWholeArchiveFlags(List<String> noWholeArchiveFlags) {
-      this.noWholeArchiveFlags = noWholeArchiveFlags;
+    public Builder setAllLTOArtifacts(Iterable<LTOBackendArtifacts> allLTOArtifacts) {
+      this.allLTOBackendArtifacts = allLTOArtifacts;
       return this;
     }
   }
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java
index 7531632..c4ea2be 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java
@@ -17,8 +17,8 @@
 import static com.google.common.truth.Truth.assertThat;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Action;
@@ -34,17 +34,18 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CppLinkActionConfigs.CppLinkPlatform;
 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.LinkerInputs.LibraryToLink;
 import com.google.devtools.build.lib.vfs.PathFragment;
-import java.io.IOException;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/** Tests for {@link CppLinkAction}. */
+/**
+ * Tests for {@link CppLinkAction}.
+ */
 @RunWith(JUnit4.class)
 public class CppLinkActionTest extends BuildViewTestCase {
   private RuleContext createDummyRuleContext() throws Exception {
@@ -65,18 +66,6 @@
           }
         }, masterConfig);
   }
-  
-  private final FeatureConfiguration getMockFeatureConfiguration() throws Exception {
-    return CcToolchainFeaturesTest.buildFeatures(
-            CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.LINUX))
-        .getFeatureConfiguration(
-            Link.LinkTargetType.EXECUTABLE.getActionName(),
-            Link.LinkTargetType.DYNAMIC_LIBRARY.getActionName(),
-            Link.LinkTargetType.STATIC_LIBRARY.getActionName(),
-            Link.LinkTargetType.PIC_STATIC_LIBRARY.getActionName(),
-            Link.LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY.getActionName(),
-            Link.LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY.getActionName());
-  }
 
   @Test
   public void testToolchainFeatureFlags() throws Exception {
@@ -104,9 +93,9 @@
                 "out",
                 ImmutableList.<Artifact>of(),
                 ImmutableList.<LibraryToLink>of(),
-                featureConfiguration,
-                false)
+                featureConfiguration)
             .build();
+    assertThat(Joiner.on(" ").join(linkAction.getArgv())).contains("mock_tool");
     assertThat(linkAction.getArgv()).contains("some_flag");
   }
 
@@ -129,8 +118,7 @@
                 "out",
                 ImmutableList.<Artifact>of(),
                 ImmutableList.<LibraryToLink>of(),
-                featureConfiguration,
-                false)
+                featureConfiguration)
             .build();
     assertThat(linkAction.getEnvironment()).containsEntry("foo", "bar");
   }
@@ -147,8 +135,6 @@
     final Artifact oFile = getSourceArtifact("cc/a.o");
     final Artifact oFile2 = getSourceArtifact("cc/a2.o");
     final Artifact interfaceSoBuilder = getBinArtifactWithNoOwner("foo/build_interface_so");
-    final FeatureConfiguration featureConfiguration = getMockFeatureConfiguration();
-
     ActionTester.runTest(
         128,
         new ActionCombinationFactory() {
@@ -172,7 +158,7 @@
             builder.setWholeArchive((i & 16) == 0);
             builder.setFake((i & 32) == 0);
             builder.setRuntimeSolibDir((i & 64) == 0 ? null : new PathFragment("so1"));
-            builder.setFeatureConfiguration(featureConfiguration);
+            builder.setFeatureConfiguration(new FeatureConfiguration());
 
             return builder.build();
           }
@@ -191,8 +177,6 @@
     final Artifact oFile = getSourceArtifact("cc/a.o");
     final Artifact oFile2 = getSourceArtifact("cc/a2.o");
     final Artifact interfaceSoBuilder = getBinArtifactWithNoOwner("foo/build_interface_so");
-    final FeatureConfiguration featureConfiguration = getMockFeatureConfiguration();
-
     ActionTester.runTest(
         4,
         new ActionCombinationFactory() {
@@ -210,7 +194,6 @@
                 (i & 1) == 0 ? ImmutableList.of(oFile) : ImmutableList.of(oFile2));
             builder.setLinkType(
                 (i & 2) == 0 ? LinkTargetType.STATIC_LIBRARY : LinkTargetType.DYNAMIC_LIBRARY);
-            builder.setFeatureConfiguration(featureConfiguration);
             return builder.build();
           }
         });
@@ -271,8 +254,7 @@
                 "binary2",
                 objects.build(),
                 ImmutableList.<LibraryToLink>of(),
-                new FeatureConfiguration(),
-                false)
+                new FeatureConfiguration())
             .setFake(true)
             .build();
 
@@ -303,8 +285,7 @@
       String outputPath,
       Iterable<Artifact> nonLibraryInputs,
       ImmutableList<LibraryToLink> libraryInputs,
-      FeatureConfiguration featureConfiguration,
-      boolean shouldIncludeToolchain)
+      FeatureConfiguration featureConfiguration)
       throws Exception {
     RuleContext ruleContext = createDummyRuleContext();
     CppLinkActionBuilder builder =
@@ -313,7 +294,7 @@
                 new Artifact(
                     new PathFragment(outputPath), getTargetConfiguration().getBinDirectory()),
                 ruleContext.getConfiguration(),
-                shouldIncludeToolchain ? CppHelper.getToolchain(ruleContext) : null)
+                null)
             .addNonLibraryInputs(nonLibraryInputs)
             .addLibraries(NestedSetBuilder.wrap(Order.LINK_ORDER, libraryInputs))
             .setLinkType(type)
@@ -325,17 +306,6 @@
             .setFeatureConfiguration(featureConfiguration);
     return builder;
   }
-  
-  private CppLinkActionBuilder createLinkBuilder(Link.LinkTargetType type) throws Exception {
-    PathFragment output = new PathFragment("dummyRuleContext/output/path.xyz");
-    return createLinkBuilder(
-        type,
-        output.getPathString(),
-        ImmutableList.<Artifact>of(),
-        ImmutableList.<LibraryToLink>of(),
-        new FeatureConfiguration(),
-        true);
-  }
 
   public Artifact getOutputArtifact(String relpath) {
     return new Artifact(
@@ -343,70 +313,4 @@
         getTargetConfiguration().getBinDirectory(),
         getTargetConfiguration().getBinFragment().getRelative(relpath));
   }
-
-  private Artifact scratchArtifact(String s) {
-    try {
-      return new Artifact(
-          scratch.overwriteFile(outputBase.getRelative("WORKSPACE").getRelative(s).toString()),
-          Root.asDerivedRoot(scratch.dir(outputBase.getRelative("WORKSPACE").toString())));
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private void assertError(String expectedSubstring, CppLinkActionBuilder builder) {
-    try {
-      builder.build();
-      fail();
-    } catch (RuntimeException e) {
-      assertThat(e.getMessage()).contains(expectedSubstring);
-    }
-  }
-
-  @Test
-  public void testInterfaceOutputWithoutBuildingDynamicLibraryIsError() throws Exception {
-    CppLinkActionBuilder builder =
-        createLinkBuilder(LinkTargetType.EXECUTABLE)
-            .setInterfaceOutput(scratchArtifact("FakeInterfaceOutput"));
-
-    assertError("Interface output can only be used with non-fake DYNAMIC_LIBRARY targets", builder);
-  }
-
-  @Test
-  public void testStaticLinkWithDynamicIsError() throws Exception {
-    CppLinkActionBuilder builder =
-        createLinkBuilder(LinkTargetType.STATIC_LIBRARY).setLinkStaticness(LinkStaticness.DYNAMIC);
-
-    assertError("static library link must be static", builder);
-  }
-
-  @Test
-  public void testStaticLinkWithSymbolsCountOutputIsError() throws Exception {
-    CppLinkActionBuilder builder =
-        createLinkBuilder(LinkTargetType.STATIC_LIBRARY)
-            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
-            .setSymbolCountsOutput(scratchArtifact("dummySymbolCounts"));
-
-    assertError("the symbol counts output must be null for static links", builder);
-  }
-
-  @Test
-  public void testStaticLinkWithNativeDepsIsError() throws Exception {
-    CppLinkActionBuilder builder =
-        createLinkBuilder(LinkTargetType.STATIC_LIBRARY)
-            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
-            .setNativeDeps(true);
-
-    assertError("the native deps flag must be false for static links", builder);
-  }
-
-  @Test
-  public void testStaticLinkWithWholeArchiveIsError() throws Exception {
-    CppLinkActionBuilder builder =
-        createLinkBuilder(LinkTargetType.STATIC_LIBRARY)
-            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
-            .setWholeArchive(true);
-
-    assertError("the need whole archive flag must be false for static links", builder);
-  }
 }
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
deleted file mode 100644
index 50fdeba..0000000
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2016 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.common.truth.Truth.assertThat;
-
-import com.google.common.collect.Iterables;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests that {@code CppLinkAction} is populated with the correct build variables. */
-@RunWith(JUnit4.class)
-public class LinkBuildVariablesTest extends BuildViewTestCase {
-
-  private CppLinkAction getCppLinkAction(ConfiguredTarget target, Link.LinkTargetType type) {
-    Artifact linkerOutput = null;
-    switch (type) {
-      case STATIC_LIBRARY:
-      case ALWAYS_LINK_STATIC_LIBRARY:
-        linkerOutput = getBinArtifact("lib" + target.getLabel().getName() + ".a", target);
-        break;
-      case PIC_STATIC_LIBRARY:
-      case ALWAYS_LINK_PIC_STATIC_LIBRARY:
-        linkerOutput = getBinArtifact("lib" + target.getLabel().getName() + "pic.a", target);
-        break;
-      case DYNAMIC_LIBRARY:
-        linkerOutput = getBinArtifact("lib" + target.getLabel().getName() + ".so", target);
-        break;
-      case EXECUTABLE:
-        linkerOutput = getExecutable(target);
-        break;
-      default:
-        throw new IllegalArgumentException(
-            String.format("Cannot get CppLinkAction for link type %s", type));
-    }
-    return (CppLinkAction) getGeneratingAction(linkerOutput);
-  }
-
-  private Variables getLinkBuildVariables(ConfiguredTarget target, Link.LinkTargetType type) {
-    return getCppLinkAction(target, type).getLinkCommandLine().getBuildVariables();
-  }
-
-  private List<String> getVariableValue(Variables variables, String variable) throws Exception {
-    FeatureConfiguration mockFeatureConfiguration =
-        CcToolchainFeaturesTest.buildFeatures(
-                "feature {",
-                "   name: 'a'",
-                "   flag_set {",
-                "   action: 'foo'",
-                "      flag_group {",
-                "         flag: '%{" + variable + "}'",
-                "      }",
-                "   }",
-                "}")
-            .getFeatureConfiguration("a");
-    return mockFeatureConfiguration.getCommandLine("foo", variables);
-  }
-
-  @Test
-  public void testLinkstampBuildVariable() throws Exception {
-    scratch.file(
-        "x/BUILD",
-        "cc_binary(",
-        "   name = 'bin',",
-        "   srcs = ['a.cc'],",
-        "   deps = [':lib'],",
-        ")",
-        "cc_library(",
-        "   name = 'lib',",
-        "   srcs = ['b.cc'],",
-        "   linkstamp = 'c.cc',",
-        ")");
-    scratch.file("x/a.cc");
-    scratch.file("x/b.cc");
-    scratch.file("x/c.cc");
-
-    ConfiguredTarget target = getConfiguredTarget("//x:bin");
-    Variables variables = getLinkBuildVariables(target, Link.LinkTargetType.EXECUTABLE);
-    List<String> variableValue =
-        getVariableValue(variables, CppLinkActionBuilder.LINKSTAMP_PATHS_VARIABLE);
-    assertThat(Iterables.getOnlyElement(variableValue)).contains("c.o");
-  }
-
-  @Test
-  public void testForcePicBuildVariable() throws Exception {
-    useConfiguration("--force_pic");
-    scratch.file("x/BUILD", "cc_binary(", "   name = 'bin',", "   srcs = ['a.cc'],", ")");
-    scratch.file("x/a.cc");
-
-    ConfiguredTarget target = getConfiguredTarget("//x:bin");
-    Variables variables = getLinkBuildVariables(target, Link.LinkTargetType.EXECUTABLE);
-    List<String> variableValue =
-        getVariableValue(variables, CppLinkActionBuilder.FORCE_PIC_VARIABLE);
-    assertThat(variableValue).contains("");
-  }
-
-  @Test
-  public void testWholeArchiveBuildVariables() throws Exception {
-    scratch.file(
-        "x/BUILD",
-        "cc_binary(",
-        "   name = 'bin.so',",
-        "   srcs = ['a.cc'],",
-        "   linkopts = ['-shared'],",
-        "   linkstatic = 1",
-        ")");
-    scratch.file("x/a.cc");
-
-    ConfiguredTarget target = getConfiguredTarget("//x:bin.so");
-    Variables variables = getLinkBuildVariables(target, Link.LinkTargetType.EXECUTABLE);
-    List<String> variableValue =
-        getVariableValue(variables, CppLinkActionBuilder.GLOBAL_WHOLE_ARCHIVE_VARIABLE);
-    assertThat(variableValue).contains("");
-  }
-}