aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Lukacs Berki <lberki@google.com>2016-08-02 09:37:05 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2016-08-02 11:15:58 +0000
commit5592a0aae2bebfbea278fdf8125bf26831a65975 (patch)
tree823197e039564ef999550bc631885b7135a4afe4 /src
parentb93a1220f7009a972305eb19f1e4d96fbb65e40c (diff)
*** Reason for rollback *** -- MOS_MIGRATED_REVID=129078102
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java25
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java22
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java573
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java297
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java690
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java120
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java134
9 files changed, 606 insertions, 1271 deletions
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 f25fc94e79..a763713938 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 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
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 f935b4faac..9ba846a701 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.concurrent.ThreadSafety.Immutable;
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 @@ public class CcToolchainFeatures implements Serializable {
*/
@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 @@ public class CcToolchainFeatures implements Serializable {
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 03212b9fc2..1e14df9dc6 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.concurrent.ThreadSafety.Immutable;
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.build.lib.view.config.crosstool.CrosstoolConfig.LipoM
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 @@ public class CppConfiguration extends BuildConfiguration.Fragment {
return result.build();
}
-
private boolean linkActionsAreConfigured(CToolchain toolchain) {
for (LinkTargetType type : LinkTargetType.values()) {
boolean typeIsConfigured = false;
@@ -714,17 +713,6 @@ public class CppConfiguration extends BuildConfiguration.Fragment {
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 @@ public class CppConfiguration extends BuildConfiguration.Fragment {
+ " 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 @@ public class CppConfiguration extends BuildConfiguration.Fragment {
+ " }"
+ " }"
+ " 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 cda2e26233..3ec9843777 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 @@ package com.google.devtools.build.lib.rules.cpp;
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.NestedSetBuilder;
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.rules.cpp.LinkerInputs.LibraryToLink;
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.LinkedHashSet;
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 @@ public class CppLinkActionBuilder {
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 @@ public class CppLinkActionBuilder {
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 @@ public class CppLinkActionBuilder {
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 @@ public class CppLinkActionBuilder {
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 @@ public class CppLinkActionBuilder {
? 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 @@ public class CppLinkActionBuilder {
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 @@ public class CppLinkActionBuilder {
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 @@ public class CppLinkActionBuilder {
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 @@ public class CppLinkActionBuilder {
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 a359350834..0000000000
--- 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 13866e81d5..d3cbeaf3e0 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.FileType;
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.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
+
import javax.annotation.Nullable;
/**
@@ -360,6 +362,11 @@ public final class CppModel {
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 @@ public final class CppModel {
.setLinkType(linkType)
.setLinkStaticness(LinkStaticness.FULLY_STATIC)
.setFeatureConfiguration(featureConfiguration)
+ .setBuildVariables(linkBuildVariables())
.build();
env.registerAction(maybePicAction);
result.addStaticLibrary(maybePicAction.getOutputLibrary());
@@ -861,6 +869,7 @@ public final class CppModel {
.setLinkType(picLinkType)
.setLinkStaticness(LinkStaticness.FULLY_STATIC)
.setFeatureConfiguration(featureConfiguration)
+ .setBuildVariables(linkBuildVariables())
.build();
env.registerAction(picAction);
result.addPicStaticLibrary(picAction.getOutputLibrary());
@@ -904,7 +913,8 @@ public final class CppModel {
.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 c5cb3017ed..96b5a3bb3c 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 @@ package com.google.devtools.build.lib.rules.cpp;
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.cmdline.Label;
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 @@ public final class LinkCommandLine extends CommandLine {
@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 @@ public final class LinkCommandLine extends CommandLine {
@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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
}
}
}
-
- 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;
-
- 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());
+ // 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());
+ 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;
-
- 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();
+ addInputFileLinkOptions(argv, /*needWholeArchive=*/ false);
+ break;
+
+ 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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
}
/**
+ * 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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 final class LinkCommandLine extends CommandLine {
}
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
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 @@ public final class LinkCommandLine extends CommandLine {
}
/**
+ * 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 @@ public final class LinkCommandLine extends CommandLine {
}
/**
+ * 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 @@ public final class LinkCommandLine extends CommandLine {
return this;
}
- public Builder setParamFile(Artifact paramFile) {
- this.paramFile = paramFile;
- return this;
- }
-
- public Builder setBuildVariables(Variables variables) {
- this.variables = variables;
+ public Builder setNeedWholeArchive(boolean needWholeArchive) {
+ this.needWholeArchive = needWholeArchive;
return this;
}
- public Builder setRuntimeSolibDir(PathFragment runtimeSolibDir) {
- this.runtimeSolibDir = runtimeSolibDir;
+ public Builder setParamFile(Artifact paramFile) {
+ this.paramFile = paramFile;
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 7531632e8a..c4ea2be93f 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 @@ package com.google.devtools.build.lib.rules.cpp;
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.analysis.util.BuildViewTestCase;
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 @@ public class CppLinkActionTest extends BuildViewTestCase {
}
}, 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 @@ public class CppLinkActionTest extends BuildViewTestCase {
"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 @@ public class CppLinkActionTest extends BuildViewTestCase {
"out",
ImmutableList.<Artifact>of(),
ImmutableList.<LibraryToLink>of(),
- featureConfiguration,
- false)
+ featureConfiguration)
.build();
assertThat(linkAction.getEnvironment()).containsEntry("foo", "bar");
}
@@ -147,8 +135,6 @@ public class CppLinkActionTest extends BuildViewTestCase {
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 @@ public class CppLinkActionTest extends BuildViewTestCase {
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 @@ public class CppLinkActionTest extends BuildViewTestCase {
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 @@ public class CppLinkActionTest extends BuildViewTestCase {
(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 @@ public class CppLinkActionTest extends BuildViewTestCase {
"binary2",
objects.build(),
ImmutableList.<LibraryToLink>of(),
- new FeatureConfiguration(),
- false)
+ new FeatureConfiguration())
.setFake(true)
.build();
@@ -303,8 +285,7 @@ public class CppLinkActionTest extends BuildViewTestCase {
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 @@ public class CppLinkActionTest extends BuildViewTestCase {
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 @@ public class CppLinkActionTest extends BuildViewTestCase {
.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 @@ public class CppLinkActionTest extends BuildViewTestCase {
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 50fdebad0f..0000000000
--- 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("");
- }
-}