aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/ArtifactCategory.java162
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java28
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java169
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java68
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java37
8 files changed, 418 insertions, 71 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/ArtifactCategory.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/ArtifactCategory.java
new file mode 100644
index 0000000000..04036faf6f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/ArtifactCategory.java
@@ -0,0 +1,162 @@
+// 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 com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * A category of artifacts that are candidate input/output to an action, for which the toolchain can
+ * select a single artifact.
+ */
+public enum ArtifactCategory {
+ STATIC_LIBRARY {
+ @Override
+ public String getCategoryName() {
+ return STATIC_LIBRARY_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of("base_name", ruleContext.getLabel().getName());
+ }
+ },
+
+ PIC_STATIC_LIBRARY {
+ @Override
+ public String getCategoryName() {
+ return PIC_STATIC_LIBRARY_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of("base_name", ruleContext.getLabel().getName());
+ }
+ },
+
+ ALWAYS_LINK_STATIC_LIBRARY {
+ @Override
+ public String getCategoryName() {
+ return ALWAYS_LINK_STATIC_LIBRARY_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of("base_name", ruleContext.getLabel().getName());
+ }
+ },
+
+ ALWAYS_LINK_PIC_STATIC_LIBRARY {
+ @Override
+ public String getCategoryName() {
+ return ALWAYS_LINK_PIC_STATIC_LIBRARY_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of("base_name", ruleContext.getLabel().getName());
+ }
+ },
+
+ DYNAMIC_LIBRARY {
+ @Override
+ public String getCategoryName() {
+ return DYNAMIC_LIBRARY_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of("base_name", ruleContext.getLabel().getName());
+ }
+ },
+
+ EXECUTABLE {
+ @Override
+ public String getCategoryName() {
+ return EXECUTABLE_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of("base_name", ruleContext.getLabel().getName());
+ }
+ },
+
+ INTERFACE {
+ @Override
+ public String getCategoryName() {
+ return INTERFACE_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of("base_name", ruleContext.getLabel().getName());
+ }
+ },
+
+ DEBUG_SYMBOLS {
+ @Override
+ public String getCategoryName() {
+ return DEBUG_SYMBOL_CATEGORY_NAME;
+ }
+
+ @Override
+ public ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext) {
+ return ImmutableMap.of();
+ }
+ };
+
+ /** Error for template evaluation failure. */
+ @VisibleForTesting
+ public static final String TEMPLATE_EVAL_FAILURE =
+ "Error evaluating file name pattern for artifact category %s: %s";
+
+ @VisibleForTesting public static final String STATIC_LIBRARY_CATEGORY_NAME = "static_library";
+
+ @VisibleForTesting
+ public static final String PIC_STATIC_LIBRARY_CATEGORY_NAME = "pic_static_library";
+
+ @VisibleForTesting
+ public static final String ALWAYS_LINK_STATIC_LIBRARY_CATEGORY_NAME = "alwayslink_static_library";
+
+ @VisibleForTesting
+ public static final String ALWAYS_LINK_PIC_STATIC_LIBRARY_CATEGORY_NAME =
+ "alwayslink_pic_static_library";
+
+ @VisibleForTesting public static final String DYNAMIC_LIBRARY_CATEGORY_NAME = "dynamic_library";
+ @VisibleForTesting public static final String EXECUTABLE_CATEGORY_NAME = "executable";
+ @VisibleForTesting public static final String INTERFACE_CATEGORY_NAME = "interface_library";
+ private static final String DEBUG_SYMBOL_CATEGORY_NAME = "debug_symbol";
+
+ /** Returns the name of the category. */
+ public abstract String getCategoryName();
+
+ /** Returns an artifact given a templated name. */
+ public Artifact getArtifactForName(String artifactName, RuleContext ruleContext) {
+ PathFragment name =
+ new PathFragment(ruleContext.getLabel().getName()).replaceName(artifactName);
+ return ruleContext.getPackageRelativeArtifact(
+ name, ruleContext.getConfiguration().getBinDirectory());
+ }
+
+ /**
+ * Returns a map of candidate template variables to their values. For example, the entry (foo,
+ * bar) indicates that the crosstool artifact name "library_%{foo}.extension" should be templated
+ * to "library_bar.extension".
+ */
+ public abstract ImmutableMap<String, String> getTemplateVariables(RuleContext ruleContext);
+}
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 f202ce123c..eef2b319de 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
@@ -156,8 +156,9 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
return CcBinary.init(semantics, context, /*fake =*/ false, /*isTest =*/ false);
}
- public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleContext, boolean fake,
- boolean isTest) throws InterruptedException {
+ public static ConfiguredTarget init(
+ CppSemantics semantics, RuleContext ruleContext, boolean fake, boolean isTest)
+ throws InterruptedException, RuleErrorException {
ruleContext.checkSrcsSamePackage(true);
FeatureConfiguration featureConfiguration = CcCommon.configureFeatures(ruleContext);
CcCommon common = new CcCommon(ruleContext);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index e7db2a5273..896ead8c13 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -106,12 +106,16 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory {
return builder.build();
}
- public static void init(CppSemantics semantics, RuleContext ruleContext,
- RuleConfiguredTargetBuilder targetBuilder, LinkTargetType linkType,
+ public static void init(
+ CppSemantics semantics,
+ RuleContext ruleContext,
+ RuleConfiguredTargetBuilder targetBuilder,
+ LinkTargetType linkType,
boolean neverLink,
boolean linkStatic,
boolean collectLinkstamp,
- boolean addDynamicRuntimeInputArtifactsToRunfiles) {
+ boolean addDynamicRuntimeInputArtifactsToRunfiles)
+ throws RuleErrorException {
FeatureConfiguration featureConfiguration = CcCommon.configureFeatures(ruleContext);
final CcCommon common = new CcCommon(ruleContext);
PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext);
@@ -186,19 +190,19 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory {
// doesn't support it, then register an action which complains when triggered,
// which only happens when some rule explicitly depends on the dynamic library.
if (!createDynamicLibrary && !supportsDynamicLinker) {
- Artifact solibArtifact = CppHelper.getLinkedArtifact(
- ruleContext, LinkTargetType.DYNAMIC_LIBRARY);
+ Artifact solibArtifact =
+ CppHelper.getLinuxLinkedArtifact(ruleContext, LinkTargetType.DYNAMIC_LIBRARY);
ruleContext.registerAction(new FailAction(ruleContext.getActionOwner(),
ImmutableList.of(solibArtifact), "Toolchain does not support dynamic linking"));
} else if (!createDynamicLibrary
&& ruleContext.attributes().isConfigurable("srcs", BuildType.LABEL_LIST)) {
- // If "srcs" is configurable, the .so output is always declared because the logic that
- // determines implicit outs doesn't know which value of "srcs" will ultimately get chosen. Here,
- // where we *do* have the correct value, it may not contain any source files to generate an
- // .so with. If that's the case, register a fake generating action to prevent a "no generating
- // action for this artifact" error.
- Artifact solibArtifact = CppHelper.getLinkedArtifact(
- ruleContext, LinkTargetType.DYNAMIC_LIBRARY);
+ // If "srcs" is configurable, the .so output is always declared because the logic that
+ // determines implicit outs doesn't know which value of "srcs" will ultimately get chosen.
+ // Here, where we *do* have the correct value, it may not contain any source files to
+ // generate an .so with. If that's the case, register a fake generating action to prevent
+ // a "no generating action for this artifact" error.
+ Artifact solibArtifact =
+ CppHelper.getLinuxLinkedArtifact(ruleContext, LinkTargetType.DYNAMIC_LIBRARY);
ruleContext.registerAction(new FailAction(ruleContext.getActionOwner(),
ImmutableList.of(solibArtifact), "configurable \"srcs\" triggers an implicit .so output "
+ "even though there are no sources to compile in this configuration"));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
index 401fefd881..40b1b8b7df 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
@@ -39,6 +39,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode;
@@ -134,7 +135,6 @@ public final class CcLibraryHelper {
Link.LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY.getActionName(),
Link.LinkTargetType.EXECUTABLE.getActionName()));
-
private final FileTypeSet sourceTypeSet;
private final Set<String> actionConfigSet;
@@ -851,8 +851,10 @@ public final class CcLibraryHelper {
/**
* Create the C++ compile and link actions, and the corresponding C++-related providers.
+ *
+ * @throws RuleErrorException
*/
- public Info build() {
+ public Info build() throws RuleErrorException {
// Fail early if there is no lipo context collector on the rule - otherwise we end up failing
// in lipo optimization.
Preconditions.checkState(
@@ -1038,14 +1040,16 @@ public final class CcLibraryHelper {
if (ruleContext.attributes().get("alwayslink", Type.BOOLEAN)) {
archiveFile.add(
- CppHelper.getLinkedArtifact(ruleContext, Link.LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY));
+ CppHelper.getLinuxLinkedArtifact(
+ ruleContext, Link.LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY));
} else {
- archiveFile.add(CppHelper.getLinkedArtifact(ruleContext, Link.LinkTargetType.STATIC_LIBRARY));
+ archiveFile.add(
+ CppHelper.getLinuxLinkedArtifact(ruleContext, Link.LinkTargetType.STATIC_LIBRARY));
}
if (CppRuleClasses.shouldCreateDynamicLibrary(ruleContext.attributes())) {
dynamicLibrary.add(
- CppHelper.getLinkedArtifact(ruleContext, Link.LinkTargetType.DYNAMIC_LIBRARY));
+ CppHelper.getLinuxLinkedArtifact(ruleContext, Link.LinkTargetType.DYNAMIC_LIBRARY));
}
outputGroups.put("archive", archiveFile.build());
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 b48e03a3f7..f935b4faac 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
@@ -26,10 +26,13 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
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;
@@ -67,7 +70,7 @@ public class CcToolchainFeatures implements Serializable {
/**
* Thrown when a flag value cannot be expanded under a set of build variables.
- *
+ *
* <p>This happens for example when a flag references a variable that is not provided by the
* action, or when a flag group references multiple variables of sequence type.
*/
@@ -76,13 +79,17 @@ public class CcToolchainFeatures implements Serializable {
super(message);
}
}
-
+
+ /** Error message thrown when a toolchain does not provide a required artifact_name_pattern. */
+ public static final String MISSING_ARTIFACT_NAME_PATTERN_ERROR_TEMPLATE =
+ "Toolchain must provide artifact_name_pattern for category %s";
+
/**
* A piece of a single string value.
- *
- * <p>A single value can contain a combination of text and variables (for example
- * "-f %{var1}/%{var2}"). We split the string into chunks, where each chunk represents either a
- * text snippet, or a variable that is to be replaced.
+ *
+ * <p>A single value can contain a combination of text and variables (for example "-f
+ * %{var1}/%{var2}"). We split the string into chunks, where each chunk represents either a text
+ * snippet, or a variable that is to be replaced.
*/
interface StringChunk {
@@ -146,22 +153,21 @@ public class CcToolchainFeatures implements Serializable {
/**
* Parser for toolchain string values.
- *
+ *
* <p>A string value contains a snippet of text supporting variable expansion. For example, a
- * string value "-f %{var1}/%{var2}" will expand the values of the variables "var1" and "var2"
- * in the corresponding places in the string.
- *
- * <p>The {@code StringValueParser} takes a string and parses it into a list of
- * {@link StringChunk} objects, where each chunk represents either a snippet of text or a
- * variable to be expanded. In the above example, the resulting chunks would be
- * ["-f ", var1, "/", var2].
- *
+ * string value "-f %{var1}/%{var2}" will expand the values of the variables "var1" and "var2" in
+ * the corresponding places in the string.
+ *
+ * <p>The {@code StringValueParser} takes a string and parses it into a list of {@link
+ * StringChunk} objects, where each chunk represents either a snippet of text or a variable to be
+ * expanded. In the above example, the resulting chunks would be ["-f ", var1, "/", var2].
+ *
* <p>In addition to the list of chunks, the {@link StringValueParser} also provides the set of
* variables necessary for the expansion of this flag via {@link #getUsedVariables}.
- *
+ *
* <p>To get a literal percent character, "%%" can be used in the string.
*/
- private static class StringValueParser {
+ static class StringValueParser {
private final String value;
@@ -173,22 +179,18 @@ public class CcToolchainFeatures implements Serializable {
private final ImmutableList.Builder<StringChunk> chunks = ImmutableList.builder();
private final ImmutableSet.Builder<String> usedVariables = ImmutableSet.builder();
- private StringValueParser(String value) throws InvalidConfigurationException {
+ StringValueParser(String value) throws InvalidConfigurationException {
this.value = value;
parse();
}
- /**
- * @return the parsed chunks for this string.
- */
- private ImmutableList<StringChunk> getChunks() {
+ /** @return the parsed chunks for this string. */
+ ImmutableList<StringChunk> getChunks() {
return chunks.build();
}
- /**
- * @return all variable names needed to expand this string.
- */
- private ImmutableSet<String> getUsedVariables() {
+ /** @return all variable names needed to expand this string. */
+ ImmutableSet<String> getUsedVariables() {
return usedVariables.build();
}
@@ -402,14 +404,15 @@ public class CcToolchainFeatures implements Serializable {
/**
* Expands all flags in this group and adds them to {@code commandLine}.
- *
+ *
* <p>The flags of the group will be expanded either:
+ *
* <ul>
- * <li>once, if there is no variable of sequence type in any of the group's flags, or</li>
- * <li>for each element in the sequence, if there is one variable of sequence type within
- * the flags.</li>
+ * <li>once, if there is no variable of sequence type in any of the group's flags, or
+ * <li>for each element in the sequence, if there is one variable of sequence type within the
+ * flags.
* </ul>
- *
+ *
* <p>Having more than a single variable of sequence type in a single flag group is not
* supported.
*/
@@ -633,6 +636,7 @@ public class CcToolchainFeatures implements Serializable {
this.configName = actionConfig.getConfigName();
this.actionName = actionConfig.getActionName();
this.tools = actionConfig.getToolList();
+
ImmutableList.Builder<FlagSet> flagSetBuilder = ImmutableList.builder();
for (CToolchain.FlagSet flagSet : actionConfig.getFlagSetList()) {
if (!flagSet.getActionList().isEmpty()) {
@@ -694,6 +698,57 @@ public class CcToolchainFeatures implements Serializable {
}
}
}
+
+ /** A description of how artifacts of a certain type are named. */
+ @Immutable
+ private static class ArtifactNamePattern {
+
+ private final ArtifactCategory artifactCategory;
+ private final ImmutableSet<String> variables;
+ private final ImmutableList<StringChunk> chunks;
+
+ private ArtifactNamePattern(CToolchain.ArtifactNamePattern artifactNamePattern)
+ throws InvalidConfigurationException {
+
+ ArtifactCategory foundCategory = null;
+ for (ArtifactCategory artifactCategory : ArtifactCategory.values()) {
+ if (artifactNamePattern.getCategoryName().equals(artifactCategory.getCategoryName())) {
+ foundCategory = artifactCategory;
+ }
+ }
+ if (foundCategory == null) {
+ throw new ExpansionException(
+ String.format(
+ "Artifact category %s not recognized", artifactNamePattern.getCategoryName()));
+ }
+ this.artifactCategory = foundCategory;
+
+ StringValueParser parser = new StringValueParser(artifactNamePattern.getPattern());
+ this.variables = parser.getUsedVariables();
+ this.chunks = parser.getChunks();
+ }
+
+ /** Returns the ArtifactCategory for this ArtifactNamePattern. */
+ ArtifactCategory getArtifactCategory() {
+ return this.artifactCategory;
+ }
+
+ /**
+ * Returns the artifact name that pattern selects for a given rule.
+ */
+ public String getArtifactName(RuleContext ruleContext) {
+ StringBuilder result = new StringBuilder();
+ Variables.View artifactNameVariables =
+ new Variables.Builder()
+ .addAllVariables(artifactCategory.getTemplateVariables(ruleContext))
+ .build()
+ .getView(variables);
+ for (StringChunk chunk : chunks) {
+ chunk.expand(artifactNameVariables.getVariables(), result);
+ }
+ return result.toString();
+ }
+ }
/**
* Configured build variables usable by the toolchain configuration.
@@ -1132,6 +1187,9 @@ public class CcToolchainFeatures implements Serializable {
return actionConfig.getTool(enabledFeatureNames);
}
}
+
+ /** All artifact name patterns defined in this feature configuration. */
+ private final ImmutableList<ArtifactNamePattern> artifactNamePatterns;
/**
* All features and action configs in the order in which they were specified in the configuration.
@@ -1194,6 +1252,7 @@ public class CcToolchainFeatures implements Serializable {
*
* @param toolchain the toolchain configuration as specified by the user.
* @throws InvalidConfigurationException if the configuration has logical errors.
+ * @throws ArtifactNamePatternNotProvidedException
*/
@VisibleForTesting
public CcToolchainFeatures(CToolchain toolchain) throws InvalidConfigurationException {
@@ -1219,7 +1278,7 @@ public class CcToolchainFeatures implements Serializable {
selectablesByName.put(actionConfig.getName(), actionConfig);
actionConfigsByActionName.put(actionConfig.getActionName(), actionConfig);
}
-
+
this.selectables = selectablesBuilder.build();
this.selectablesByName = ImmutableMap.copyOf(selectablesByName);
@@ -1228,6 +1287,14 @@ public class CcToolchainFeatures implements Serializable {
this.actionConfigsByActionName = actionConfigsByActionName.build();
+ ImmutableList.Builder<ArtifactNamePattern> artifactNamePatternsBuilder =
+ ImmutableList.builder();
+ for (CToolchain.ArtifactNamePattern artifactNamePattern :
+ toolchain.getArtifactNamePatternList()) {
+ artifactNamePatternsBuilder.add(new ArtifactNamePattern(artifactNamePattern));
+ }
+ this.artifactNamePatterns = artifactNamePatternsBuilder.build();
+
// Next, we build up all forward references for 'implies' and 'requires' edges.
ImmutableMultimap.Builder<CrosstoolSelectable, CrosstoolSelectable> implies =
ImmutableMultimap.builder();
@@ -1383,10 +1450,42 @@ public class CcToolchainFeatures implements Serializable {
}
/**
+ * Returns the artifact selected by the toolchain for the given action type and action category,
+ * or null if the category is not supported by the action config.
+ */
+ Artifact getArtifactForCategory(ArtifactCategory artifactCategory, RuleContext ruleContext)
+ throws ExpansionException {
+ ArtifactNamePattern patternForCategory = null;
+ for (ArtifactNamePattern artifactNamePattern : artifactNamePatterns) {
+ if (artifactNamePattern.getArtifactCategory() == artifactCategory) {
+ patternForCategory = artifactNamePattern;
+ }
+ }
+ if (patternForCategory == null) {
+ throw new ExpansionException(
+ String.format(
+ MISSING_ARTIFACT_NAME_PATTERN_ERROR_TEMPLATE, artifactCategory.getCategoryName()));
+ }
+
+ String templatedName = patternForCategory.getArtifactName(ruleContext);
+ return artifactCategory.getArtifactForName(templatedName, ruleContext);
+ }
+
+ /** Returns true if the toolchain defines an ArtifactNamePattern for the given category. */
+ boolean hasPatternForArtifactCategory(ArtifactCategory artifactCategory) {
+ for (ArtifactNamePattern artifactNamePattern : artifactNamePatterns) {
+ if (artifactNamePattern.getArtifactCategory() == artifactCategory) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Implements the feature selection algorithm.
- *
- * <p>Feature selection is done by first enabling all features reachable by an 'implies' edge,
- * and then iteratively pruning features that have unmet requirements.
+ *
+ * <p>Feature selection is done by first enabling all features reachable by an 'implies' edge, and
+ * then iteratively pruning features that have unmet requirements.
*/
private class FeatureSelection {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index 4a20c22d82..b3367f4048 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -324,10 +324,8 @@ public class CppHelper {
src.getRoot());
}
- /**
- * Returns the linked artifact.
- */
- public static Artifact getLinkedArtifact(RuleContext ruleContext, LinkTargetType linkType) {
+ /** Returns the linked artifact for linux. */
+ public static Artifact getLinuxLinkedArtifact(RuleContext ruleContext, LinkTargetType linkType) {
PathFragment name = new PathFragment(ruleContext.getLabel().getName());
if (linkType != LinkTargetType.EXECUTABLE) {
name = name.replaceName("lib" + name.getBaseName() + linkType.getExtension());
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 38aa8b9299..13866e81d5 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
@@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FailAction;
import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
@@ -26,7 +27,9 @@ import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs.Builder;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
@@ -737,6 +740,49 @@ public final class CppModel {
}
/**
+ * Returns the linked artifact resulting from a linking of the given type. Consults the feature
+ * configuration to obtain an action_config that provides the artifact. If the feature
+ * configuration provides no artifact, uses a default.
+ *
+ * <p>We cannot assume that the feature configuration contains an action_config for the link
+ * action, because the linux link action depends on hardcoded values in
+ * LinkCommandLine.getRawLinkArgv(), which are applied on the condition that an action_config is
+ * not present.
+ * TODO(b/30393154): Assert that the given link action has an action_config.
+ *
+ * @throws RuleErrorException
+ */
+ private Artifact getLinkedArtifact(LinkTargetType linkTargetType) throws RuleErrorException {
+ Artifact result = null;
+ Artifact linuxDefault = CppHelper.getLinuxLinkedArtifact(ruleContext, linkTargetType);
+ CcToolchainFeatures toolchain = CppHelper.getToolchain(ruleContext).getFeatures();
+
+ if (toolchain.hasPatternForArtifactCategory(linkTargetType.getLinkerOutput())) {
+ try {
+ result = toolchain.getArtifactForCategory(linkTargetType.getLinkerOutput(), ruleContext);
+ } catch (ExpansionException e) {
+ ruleContext.throwWithRuleError(e.getMessage());
+ }
+ } else {
+ return linuxDefault;
+ }
+ // If the linked artifact is not the linux default, then a FailAction is generated for the
+ // linux default to satisfy the requirement of the implicit output.
+ // TODO(b/30132703): Remove the implicit outputs of cc_library.
+ if (!result.equals(linuxDefault)) {
+ ruleContext.registerAction(
+ new FailAction(
+ ruleContext.getActionOwner(),
+ ImmutableList.of(linuxDefault),
+ String.format(
+ "the given toolchain supports creation of %s instead of %s",
+ linuxDefault.getExecPathString(), result.getExecPathString())));
+ }
+
+ return result;
+ }
+
+ /**
* Constructs the C++ linker actions. It generally generates two actions, one for a static library
* and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
* it additionally creates a third action to generate a PIC static library.
@@ -745,8 +791,11 @@ public final class CppModel {
* can be used for linking, but doesn't contain any executable code. This increases the number of
* cache hits for link actions. Call {@link #setAllowInterfaceSharedObjects(boolean)} to enable
* this behavior.
+ *
+ * @throws RuleErrorException
*/
- public CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs) {
+ public CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs)
+ throws RuleErrorException {
// For now only handle static links. Note that the dynamic library link below ignores linkType.
// TODO(bazel-team): Either support non-static links or move this check to setLinkType().
Preconditions.checkState(linkType.isStaticLibraryLink(), "can only handle static links");
@@ -775,7 +824,11 @@ public final class CppModel {
//
// Presumably, it is done this way because the .a file is an implicit output of every cc_library
// rule, so we can't use ".pic.a" that in the always-PIC case.
- Artifact linkedArtifact = CppHelper.getLinkedArtifact(ruleContext, linkType);
+
+ // If the crosstool is configured to select an output artifact, we use that selection.
+ // Otherwise, we use linux defaults.
+ Artifact linkedArtifact = getLinkedArtifact(linkType);
+
CppLinkAction maybePicAction =
newLinkActionBuilder(linkedArtifact)
.addNonLibraryInputs(ccOutputs.getObjectFiles(usePicForBinaries))
@@ -796,7 +849,10 @@ public final class CppModel {
? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY
: LinkTargetType.PIC_STATIC_LIBRARY;
- Artifact picArtifact = CppHelper.getLinkedArtifact(ruleContext, picLinkType);
+ // If the crosstool is configured to select an output artifact, we use that selection.
+ // Otherwise, we use linux defaults.
+ Artifact picArtifact = getLinkedArtifact(picLinkType);
+
CppLinkAction picAction =
newLinkActionBuilder(picArtifact)
.addNonLibraryInputs(ccOutputs.getObjectFiles(true))
@@ -817,7 +873,9 @@ public final class CppModel {
// Create dynamic library.
Artifact soImpl;
if (soImplArtifact == null) {
- soImpl = CppHelper.getLinkedArtifact(ruleContext, LinkTargetType.DYNAMIC_LIBRARY);
+ // If the crosstool is configured to select an output artifact, we use that selection.
+ // Otherwise, we use linux defaults.
+ soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY);
} else {
soImpl = soImplArtifact;
}
@@ -826,7 +884,7 @@ public final class CppModel {
Artifact soInterface = null;
if (cppConfiguration.useInterfaceSharedObjects() && allowInterfaceSharedObjects) {
soInterface =
- CppHelper.getLinkedArtifact(ruleContext, LinkTargetType.INTERFACE_DYNAMIC_LIBRARY);
+ CppHelper.getLinuxLinkedArtifact(ruleContext, LinkTargetType.INTERFACE_DYNAMIC_LIBRARY);
sonameLinkopts = ImmutableList.of("-Wl,-soname=" +
SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), false));
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
index 38ab7e8ccf..8826b0acb7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/Link.java
@@ -94,34 +94,50 @@ public abstract class Link {
*/
public enum LinkTargetType {
/** A normal static archive. */
- STATIC_LIBRARY(".a", true, "c++-link-static-library"),
+ STATIC_LIBRARY(".a", true, "c++-link-static-library", ArtifactCategory.STATIC_LIBRARY),
/** A static archive with .pic.o object files (compiled with -fPIC). */
- PIC_STATIC_LIBRARY(".pic.a", true, "c++-link-pic-static-library"),
+ PIC_STATIC_LIBRARY(
+ ".pic.a", true, "c++-link-pic-static-library", ArtifactCategory.PIC_STATIC_LIBRARY),
/** An interface dynamic library. */
- INTERFACE_DYNAMIC_LIBRARY(".ifso", false, "c++-link-interface-dynamic-library"),
+ INTERFACE_DYNAMIC_LIBRARY(
+ ".ifso", false, "c++-link-interface-dynamic-library", ArtifactCategory.INTERFACE),
/** A dynamic library. */
- DYNAMIC_LIBRARY(".so", false, "c++-link-dynamic-library"),
+ DYNAMIC_LIBRARY(".so", false, "c++-link-dynamic-library", ArtifactCategory.DYNAMIC_LIBRARY),
/** A static archive without removal of unused object files. */
- ALWAYS_LINK_STATIC_LIBRARY(".lo", true, "c++-link-alwayslink-static-library"),
+ ALWAYS_LINK_STATIC_LIBRARY(
+ ".lo",
+ true,
+ "c++-link-alwayslink-static-library",
+ ArtifactCategory.ALWAYS_LINK_STATIC_LIBRARY),
/** A PIC static archive without removal of unused object files. */
- ALWAYS_LINK_PIC_STATIC_LIBRARY(".pic.lo", true, "c++-link-alwayslink-pic-static-library"),
+ ALWAYS_LINK_PIC_STATIC_LIBRARY(
+ ".pic.lo",
+ true,
+ "c++-link-alwayslink-pic-static-library",
+ ArtifactCategory.ALWAYS_LINK_PIC_STATIC_LIBRARY),
/** An executable binary. */
- EXECUTABLE("", false, "c++-link-executable");
+ EXECUTABLE("", false, "c++-link-executable", ArtifactCategory.EXECUTABLE);
private final String extension;
private final boolean staticLibraryLink;
private final String actionName;
+ private final ArtifactCategory linkerOutput;
- private LinkTargetType(String extension, boolean staticLibraryLink, String actionName) {
+ private LinkTargetType(
+ String extension,
+ boolean staticLibraryLink,
+ String actionName,
+ ArtifactCategory linkerOutput) {
this.extension = extension;
this.staticLibraryLink = staticLibraryLink;
this.actionName = actionName;
+ this.linkerOutput = linkerOutput;
}
public String getExtension() {
@@ -132,6 +148,11 @@ public abstract class Link {
return staticLibraryLink;
}
+ /** Returns an {@code ArtifactCategory} identifying the artifact type this link action emits. */
+ public ArtifactCategory getLinkerOutput() {
+ return linkerOutput;
+ }
+
/**
* The name of a link action with this LinkTargetType, for the purpose of crosstool feature
* selection.