aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com
diff options
context:
space:
mode:
authorGravatar John Cater <jcater@google.com>2017-07-20 19:43:20 +0200
committerGravatar Klaus Aehlig <aehlig@google.com>2017-07-21 09:14:45 +0200
commit2e56f0664d91fce3974938198d8a30e1aeef8d62 (patch)
treea3e05e61f632804e162f8c626e5e656d00905cba /src/main/java/com
parent520bbbc5ff375d3c4aebe09ee51442dd5511e7b8 (diff)
Use toolchain resolution in rule creation.
Part of #2219. Change-Id: Id4929d5ddcd57b4635af5e513eb9a09f16a78e71 PiperOrigin-RevId: 162634398
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java54
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java58
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java183
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java17
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java64
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java93
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java21
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java220
9 files changed, 615 insertions, 122 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
index 11daaa70a0..d4dbb0e97e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
@@ -205,20 +205,34 @@ public final class ConfiguredTargetFactory {
/**
* Invokes the appropriate constructor to create a {@link ConfiguredTarget} instance.
+ *
* <p>For use in {@code ConfiguredTargetFunction}.
*
* <p>Returns null if Skyframe deps are missing or upon certain errors.
*/
@Nullable
- public final ConfiguredTarget createConfiguredTarget(AnalysisEnvironment analysisEnvironment,
- ArtifactFactory artifactFactory, Target target, BuildConfiguration config,
+ public final ConfiguredTarget createConfiguredTarget(
+ AnalysisEnvironment analysisEnvironment,
+ ArtifactFactory artifactFactory,
+ Target target,
+ BuildConfiguration config,
BuildConfiguration hostConfig,
OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap,
- ImmutableMap<Label, ConfigMatchingProvider> configConditions)
+ ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ @Nullable ToolchainContext toolchainContext)
throws InterruptedException {
if (target instanceof Rule) {
- return createRule(analysisEnvironment, (Rule) target, config, hostConfig,
- prerequisiteMap, configConditions);
+ Preconditions.checkArgument(
+ toolchainContext != null,
+ "ToolchainContext should never be null when creating a ConfiguredTarget for a Rule");
+ return createRule(
+ analysisEnvironment,
+ (Rule) target,
+ config,
+ hostConfig,
+ prerequisiteMap,
+ configConditions,
+ toolchainContext);
}
// Visibility, like all package groups, doesn't have a configuration
@@ -271,10 +285,18 @@ public final class ConfiguredTargetFactory {
*/
@Nullable
private ConfiguredTarget createRule(
- AnalysisEnvironment env, Rule rule, BuildConfiguration configuration,
+ AnalysisEnvironment env,
+ Rule rule,
+ BuildConfiguration configuration,
BuildConfiguration hostConfiguration,
OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap,
- ImmutableMap<Label, ConfigMatchingProvider> configConditions) throws InterruptedException {
+ ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ ToolchainContext toolchainContext)
+ throws InterruptedException {
+
+ // Load the requested toolchains into the ToolchainContext.
+ toolchainContext.resolveToolchains(prerequisiteMap);
+
// Visibility computation and checking is done for every rule.
RuleContext ruleContext =
new RuleContext.Builder(
@@ -289,9 +311,7 @@ public final class ConfiguredTargetFactory {
.setPrerequisites(prerequisiteMap)
.setConfigConditions(configConditions)
.setUniversalFragment(ruleClassProvider.getUniversalFragment())
- // TODO(katre): Populate the actual selected toolchains.
- .setToolchainContext(
- new ToolchainContext(rule.getRuleClassObject().getRequiredToolchains(), null))
+ .setToolchainContext(toolchainContext)
.build();
if (ruleContext.hasErrors()) {
return null;
@@ -365,9 +385,10 @@ public final class ConfiguredTargetFactory {
return aspect.getDescriptor();
}
};
+
/**
- * Constructs an {@link ConfiguredAspect}. Returns null if an error occurs; in that case,
- * {@code aspectFactory} should call one of the error reporting methods of {@link RuleContext}.
+ * Constructs an {@link ConfiguredAspect}. Returns null if an error occurs; in that case, {@code
+ * aspectFactory} should call one of the error reporting methods of {@link RuleContext}.
*/
public ConfiguredAspect createAspect(
AnalysisEnvironment env,
@@ -377,9 +398,14 @@ public final class ConfiguredTargetFactory {
Aspect aspect,
OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap,
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ ToolchainContext toolchainContext,
BuildConfiguration aspectConfiguration,
BuildConfiguration hostConfiguration)
throws InterruptedException {
+
+ // Load the requested toolchains into the ToolchainContext.
+ toolchainContext.resolveToolchains(prerequisiteMap);
+
RuleContext.Builder builder = new RuleContext.Builder(
env,
associatedTarget.getTarget().getAssociatedRule(),
@@ -397,9 +423,7 @@ public final class ConfiguredTargetFactory {
.setAspectAttributes(aspect.getDefinition().getAttributes())
.setConfigConditions(configConditions)
.setUniversalFragment(ruleClassProvider.getUniversalFragment())
- // TODO(katre): Populate the actual selected toolchains.
- .setToolchainContext(
- new ToolchainContext(aspect.getDefinition().getRequiredToolchains(), null))
+ .setToolchainContext(toolchainContext)
.build();
if (ruleContext.hasErrors()) {
return null;
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
index 6eea61a62f..69fe02a01d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
@@ -22,6 +22,7 @@ import com.google.devtools.build.lib.analysis.AspectCollection.AspectCycleOnPath
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
+import com.google.devtools.build.lib.analysis.config.HostTransition;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.analysis.config.PatchTransition;
import com.google.devtools.build.lib.cmdline.Label;
@@ -93,12 +94,16 @@ public abstract class DependencyResolver {
@Nullable Aspect aspect,
ImmutableMap<Label, ConfigMatchingProvider> configConditions)
throws EvalException, InvalidConfigurationException, InterruptedException,
- InconsistentAspectOrderException {
+ InconsistentAspectOrderException {
NestedSetBuilder<Label> rootCauses = NestedSetBuilder.<Label>stableOrder();
- OrderedSetMultimap<Attribute, Dependency> outgoingEdges = dependentNodeMap(
- node, hostConfig,
- aspect != null ? ImmutableList.of(aspect) : ImmutableList.<Aspect>of(),
- configConditions, rootCauses);
+ OrderedSetMultimap<Attribute, Dependency> outgoingEdges =
+ dependentNodeMap(
+ node,
+ hostConfig,
+ aspect != null ? ImmutableList.of(aspect) : ImmutableList.<Aspect>of(),
+ configConditions,
+ /*toolchainContext=*/ null,
+ rootCauses);
if (!rootCauses.isEmpty()) {
throw new IllegalStateException(rootCauses.build().iterator().next().toString());
}
@@ -113,14 +118,13 @@ public abstract class DependencyResolver {
* <p>If {@code aspects} is empty, returns the dependent nodes of the configured target node
* representing the given target and configuration.
*
- * Otherwise {@code aspects} represents an aspect path. The function returns dependent nodes
- * of the entire path applied to given target and configuration. These are the depenent nodes
- * of the last aspect in the path.
+ * <p>Otherwise {@code aspects} represents an aspect path. The function returns dependent nodes of
+ * the entire path applied to given target and configuration. These are the depenent nodes of the
+ * last aspect in the path.
*
- * <p>This also implements the first step of applying
- * configuration transitions, namely, split transitions. This needs to be done before the labels
- * are resolved because late bound attributes depend on the configuration. A good example for this
- * is @{code :cc_toolchain}.
+ * <p>This also implements the first step of applying configuration transitions, namely, split
+ * transitions. This needs to be done before the labels are resolved because late bound attributes
+ * depend on the configuration. A good example for this is @{code :cc_toolchain}.
*
* <p>The long-term goal is that most configuration transitions be applied here. However, in order
* to do that, we first have to eliminate transitions that depend on the rule class of the
@@ -131,17 +135,19 @@ public abstract class DependencyResolver {
* This is needed to support {@link LateBoundDefault#useHostConfiguration()}.
* @param aspects the aspects applied to this target (if any)
* @param configConditions resolver for config_setting labels
- * @param rootCauses collector for dep labels that can't be (loading phase) loaded
- * @return a mapping of each attribute in this rule or aspects to its dependent nodes
+ * @param toolchainContext context information for required toolchains
+ * @param rootCauses collector for dep labels that can't be (loading phase) loaded @return a
+ * mapping of each attribute in this rule or aspects to its dependent nodes
*/
public final OrderedSetMultimap<Attribute, Dependency> dependentNodeMap(
TargetAndConfiguration node,
BuildConfiguration hostConfig,
Iterable<Aspect> aspects,
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ @Nullable ToolchainContext toolchainContext,
NestedSetBuilder<Label> rootCauses)
throws EvalException, InvalidConfigurationException, InterruptedException,
- InconsistentAspectOrderException {
+ InconsistentAspectOrderException {
Target target = node.getTarget();
BuildConfiguration config = node.getConfiguration();
OrderedSetMultimap<Attribute, Dependency> outgoingEdges = OrderedSetMultimap.create();
@@ -155,7 +161,8 @@ public abstract class DependencyResolver {
} else if (target instanceof EnvironmentGroup) {
visitTargetVisibility(node, rootCauses, outgoingEdges.get(null));
} else if (target instanceof Rule) {
- visitRule(node, hostConfig, aspects, configConditions, rootCauses, outgoingEdges);
+ visitRule(
+ node, hostConfig, aspects, configConditions, toolchainContext, rootCauses, outgoingEdges);
} else if (target instanceof PackageGroup) {
visitPackageGroup(node, (PackageGroup) target, rootCauses, outgoingEdges.get(null));
} else {
@@ -170,10 +177,11 @@ public abstract class DependencyResolver {
BuildConfiguration hostConfig,
Iterable<Aspect> aspects,
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ @Nullable ToolchainContext toolchainContext,
NestedSetBuilder<Label> rootCauses,
OrderedSetMultimap<Attribute, Dependency> outgoingEdges)
throws EvalException, InvalidConfigurationException, InconsistentAspectOrderException,
- InterruptedException{
+ InterruptedException {
Preconditions.checkArgument(node.getTarget() instanceof Rule);
BuildConfiguration ruleConfig = Preconditions.checkNotNull(node.getConfiguration());
Rule rule = (Rule) node.getTarget();
@@ -186,6 +194,12 @@ public abstract class DependencyResolver {
visitTargetVisibility(node, rootCauses, outgoingEdges.get(null));
resolveEarlyBoundAttributes(depResolver);
resolveLateBoundAttributes(depResolver, ruleConfig, hostConfig);
+
+ if (toolchainContext != null) {
+ Attribute toolchainsAttribute =
+ attributeMap.getAttributeDefinition(PlatformSemantics.TOOLCHAINS_ATTR);
+ resolveToolchainDependencies(outgoingEdges.get(toolchainsAttribute), toolchainContext);
+ }
}
/**
@@ -396,6 +410,16 @@ public abstract class DependencyResolver {
}
}
+ private void resolveToolchainDependencies(
+ Set<Dependency> dependencies, ToolchainContext toolchainContext) {
+ for (Label label : toolchainContext.getResolvedToolchainLabels()) {
+ Dependency dependency =
+ Dependency.withTransitionAndAspects(
+ label, HostTransition.INSTANCE, AspectCollection.EMPTY);
+ dependencies.add(dependency);
+ }
+ }
+
/**
* Returns the BuildOptions if the rule's attribute triggers a split in this configuration, or
* the empty collection if the attribute does not trigger a split transition or if the split
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
index 7da9d4cafa..d93c5a6dea 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/PlatformSemantics.java
@@ -18,9 +18,8 @@ import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
-import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.AttributeMap;
@@ -33,22 +32,7 @@ public class PlatformSemantics {
public static final String TARGET_PLATFORMS_ATTR = ":target_platforms";
public static final String EXECUTION_PLATFORM_ATTR = ":execution_platform";
-
- public Iterable<PlatformInfo> getTargetPlatforms(RuleContext ruleContext) {
- Iterable<PlatformInfo> platform =
- PlatformProviderUtils.platforms(
- ruleContext.getPrerequisites(
- TARGET_PLATFORMS_ATTR, RuleConfiguredTarget.Mode.DONT_CHECK));
- return platform;
- }
-
- public PlatformInfo getExecutionPlatform(RuleContext ruleContext) {
- PlatformInfo platform =
- PlatformProviderUtils.platform(
- ruleContext.getPrerequisite(
- EXECUTION_PLATFORM_ATTR, RuleConfiguredTarget.Mode.DONT_CHECK));
- return platform;
- }
+ public static final String TOOLCHAINS_ATTR = "$toolchains";
/** Implementation for the :target_platform attribute. */
public static final Attribute.LateBoundLabelList<BuildConfiguration> TARGET_PLATFORM =
@@ -62,6 +46,7 @@ public class PlatformSemantics {
return configuration.getFragment(PlatformConfiguration.class).getTargetPlatforms();
}
};
+
/** Implementation for the :execution_platform attribute. */
public static final Attribute.LateBoundLabel<BuildConfiguration> EXECUTION_PLATFORM =
new Attribute.LateBoundLabel<BuildConfiguration>(PlatformConfiguration.class) {
@@ -83,6 +68,10 @@ public class PlatformSemantics {
.add(
attr(EXECUTION_PLATFORM_ATTR, LABEL)
.value(EXECUTION_PLATFORM)
- .nonconfigurable("Used in toolchain resolution"));
+ .nonconfigurable("Used in toolchain resolution"))
+ .add(
+ attr(TOOLCHAINS_ATTR, LABEL_LIST)
+ .nonconfigurable("Used in toolchain resolution")
+ .value(ImmutableList.of()));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
index 8e3a1d08f8..fc52bd65b8 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
@@ -14,33 +14,186 @@
package com.google.devtools.build.lib.analysis;
+import static java.util.stream.Collectors.joining;
+
+import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.syntax.SkylarkDict;
-import java.util.Map;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.SkylarkIndexable;
+import com.google.devtools.build.lib.util.OrderedSetMultimap;
+import com.google.devtools.build.lib.util.Preconditions;
+import java.util.List;
+import java.util.Optional;
import javax.annotation.Nullable;
/** Contains toolchain-related information needed for a {@link RuleContext}. */
+@Immutable
+@ThreadSafe
+@SkylarkModule(
+ name = "ToolchainContext",
+ category = SkylarkModuleCategory.BUILTIN,
+ doc = "Stores toolchains available to a given rule."
+)
public class ToolchainContext {
+ public static ToolchainContext create(
+ List<Label> requiredToolchains, ImmutableBiMap<Label, Label> resolvedLabels) {
+ ToolchainContext toolchainContext =
+ new ToolchainContext(requiredToolchains, new ResolvedToolchainLabels(resolvedLabels));
+ return toolchainContext;
+ }
+
private final ImmutableList<Label> requiredToolchains;
- private final ImmutableMap<Label, ToolchainInfo> toolchains;
-
- public ToolchainContext(
- ImmutableList<Label> requiredToolchains, @Nullable Map<Label, ToolchainInfo> toolchains) {
- this.requiredToolchains = requiredToolchains;
- this.toolchains =
- toolchains == null
- ? ImmutableMap.<Label, ToolchainInfo>of()
- : ImmutableMap.copyOf(toolchains);
+
+ // Map from toolchain type labels to actual resolved toolchain labels.
+ private final ResolvedToolchainLabels resolvedToolchainLabels;
+
+ // Stores the actual ToolchainInfo provider for each toolchain type.
+ private ResolvedToolchainProviders resolvedToolchainProviders =
+ ResolvedToolchainProviders.empty();
+
+ private ToolchainContext(
+ List<Label> requiredToolchains, ResolvedToolchainLabels resolvedToolchainLabels) {
+ this.requiredToolchains = ImmutableList.copyOf(requiredToolchains);
+ this.resolvedToolchainLabels = resolvedToolchainLabels;
}
- public ImmutableList<Label> getRequiredToolchains() {
- return requiredToolchains;
+ public void resolveToolchains(OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap) {
+ if (!this.requiredToolchains.isEmpty()) {
+ this.resolvedToolchainProviders =
+ ResolvedToolchainProviders.create(resolvedToolchainLabels, prerequisiteMap);
+ }
}
- public SkylarkDict<Label, ToolchainInfo> collectToolchains() {
- return SkylarkDict.<Label, ToolchainInfo>copyOf(null, toolchains);
+ @Nullable
+ public SkylarkIndexable getResolvedToolchainProviders() {
+ return resolvedToolchainProviders;
+ }
+
+ public ImmutableSet<Label> getResolvedToolchainLabels() {
+ return resolvedToolchainLabels.getToolchainLabels();
+ }
+
+ /** Tracks the mapping from toolchain type label to the label of the actual resolved toolchain. */
+ private static class ResolvedToolchainLabels {
+ private final ImmutableBiMap<Label, Label> toolchainLabels;
+
+ private ResolvedToolchainLabels(ImmutableBiMap<Label, Label> toolchainLabels) {
+ this.toolchainLabels = toolchainLabels;
+ }
+
+ public Label getType(Label toolchainLabel) {
+ return toolchainLabels.inverse().get(toolchainLabel);
+ }
+
+ public Label getResolvedToolchainLabel(Label toolchainType) {
+ return toolchainLabels.get(toolchainType);
+ }
+
+ public ImmutableSet<Label> getToolchainLabels() {
+ return toolchainLabels.values();
+ }
+ }
+
+ /** Tracks the mapping from toolchain type label to {@link ToolchainInfo} provider. */
+ private static class ResolvedToolchainProviders implements SkylarkValue, SkylarkIndexable {
+ private static ResolvedToolchainProviders empty() {
+ return new ResolvedToolchainProviders(ImmutableMap.<Label, ToolchainInfo>of());
+ }
+
+ private static ResolvedToolchainProviders create(
+ ResolvedToolchainLabels resolvedToolchainLabels,
+ OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap) {
+ // Find the prerequisites associated with the $toolchains attribute.
+ Optional<Attribute> toolchainAttribute =
+ prerequisiteMap
+ .keys()
+ .stream()
+ .filter(attribute -> attribute.getName().equals(PlatformSemantics.TOOLCHAINS_ATTR))
+ .findFirst();
+ Preconditions.checkState(
+ toolchainAttribute.isPresent(),
+ "No toolchains attribute found while loading resolved toolchains");
+
+ ImmutableMap.Builder<Label, ToolchainInfo> toolchains = new ImmutableMap.Builder<>();
+ for (ConfiguredTarget target : prerequisiteMap.get(toolchainAttribute.get())) {
+ Label discoveredLabel = target.getLabel();
+ Label toolchainType = resolvedToolchainLabels.getType(discoveredLabel);
+ if (toolchainType != null) {
+ ToolchainInfo toolchainInfo = PlatformProviderUtils.toolchain(target);
+ toolchains.put(toolchainType, toolchainInfo);
+ }
+ }
+ return new ResolvedToolchainProviders(toolchains.build());
+ }
+
+ private final ImmutableMap<Label, ToolchainInfo> toolchains;
+
+ private ResolvedToolchainProviders(ImmutableMap<Label, ToolchainInfo> toolchains) {
+ this.toolchains = toolchains;
+ }
+
+ @Override
+ public boolean isImmutable() {
+ return true;
+ }
+
+ @Override
+ public void repr(SkylarkPrinter printer) {
+ printer.append("<toolchain_context.resolved_labels: ");
+ printer.append(toolchains.keySet().stream()
+ .map(key -> key.toString())
+ .collect(joining(", ")));
+ printer.append(">");
+ }
+
+ private Label transformKey(Object key, Location loc) throws EvalException {
+ if (key instanceof Label) {
+ Label toolchainType = (Label) key;
+ return toolchainType;
+ } else if (key instanceof String) {
+ Label toolchainType = null;
+ String rawLabel = (String) key;
+ try {
+ toolchainType = Label.parseAbsolute(rawLabel);
+ } catch (LabelSyntaxException e) {
+ throw new EvalException(
+ loc, String.format("Unable to parse toolchain %s: %s", rawLabel, e.getMessage()), e);
+ }
+ return toolchainType;
+ } else {
+ throw new EvalException(
+ loc,
+ String.format(
+ "Toolchains only supports indexing by toolchain type, got %s instead",
+ EvalUtils.getDataTypeName(key)));
+ }
+ }
+
+ @Override
+ public ToolchainInfo getIndex(Object key, Location loc) throws EvalException {
+ Label toolchainType = transformKey(key, loc);
+ return toolchains.get(toolchainType);
+ }
+
+ @Override
+ public boolean containsKey(Object key, Location loc) throws EvalException {
+ Label toolchainType = transformKey(key, loc);
+ return toolchains.containsKey(toolchainType);
+ }
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index 88eb059c47..7590bc344e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -36,7 +36,6 @@ import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.FragmentCollection;
-import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Location;
@@ -66,6 +65,7 @@ import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression.FuncallException;
import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkDict;
+import com.google.devtools.build.lib.syntax.SkylarkIndexable;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkSemanticsOptions;
import com.google.devtools.build.lib.syntax.SkylarkType;
@@ -186,7 +186,6 @@ public final class SkylarkRuleContext implements SkylarkValue {
private SkylarkRuleAttributesCollection attributesCollection;
private SkylarkRuleAttributesCollection ruleAttributesCollection;
private SkylarkClassObject splitAttributes;
- private SkylarkDict<Label, ToolchainInfo> toolchains;
// TODO(bazel-team): we only need this because of the css_binary rule.
private ImmutableMap<Artifact, Label> artifactsLabelMap;
@@ -292,10 +291,6 @@ public final class SkylarkRuleContext implements SkylarkValue {
}
makeVariables = ruleContext.getConfigurationMakeVariableContext().collectMakeVariables();
- toolchains =
- ruleContext.getToolchainContext() == null
- ? SkylarkDict.<Label, ToolchainInfo>of(null)
- : ruleContext.getToolchainContext().collectToolchains();
}
/**
@@ -315,7 +310,6 @@ public final class SkylarkRuleContext implements SkylarkValue {
splitAttributes = null;
artifactsLabelMap = null;
outputsObject = null;
- toolchains = null;
}
public void checkMutable(String attrName) throws EvalException {
@@ -852,14 +846,9 @@ public final class SkylarkRuleContext implements SkylarkValue {
}
@SkylarkCallable(structField = true, doc = "Toolchains required for this rule.")
- public SkylarkDict<Label, ToolchainInfo> toolchains() throws EvalException {
+ public SkylarkIndexable toolchains() throws EvalException {
checkMutable("toolchains");
- if (isForAspect) {
- // TODO(katre): Support toolchains on aspects.
- throw new EvalException(
- Location.BUILTIN, "'toolchains' is not available in aspect implementations");
- }
- return toolchains;
+ return ruleContext.getToolchainContext().getResolvedToolchainProviders();
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 5569a643b3..b01faa95e4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -27,6 +27,7 @@ import com.google.devtools.build.lib.analysis.DependencyResolver.InconsistentAsp
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget;
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
+import com.google.devtools.build.lib.analysis.ToolchainContext;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
@@ -54,6 +55,7 @@ import com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.Configure
import com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.DependencyEvaluationException;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider;
import com.google.devtools.build.lib.skyframe.SkylarkImportLookupFunction.SkylarkImportFailedException;
+import com.google.devtools.build.lib.skyframe.ToolchainUtil.ToolchainContextException;
import com.google.devtools.build.lib.syntax.Type.ConversionException;
import com.google.devtools.build.lib.util.OrderedSetMultimap;
import com.google.devtools.build.lib.util.Preconditions;
@@ -264,18 +266,35 @@ public final class AspectFunction implements SkyFunction {
return null;
}
+ // Determine what toolchains are needed by this target.
+ ToolchainContext toolchainContext;
+ try {
+ ImmutableList<Label> requiredToolchains = aspect.getDefinition().getRequiredToolchains();
+ toolchainContext =
+ ToolchainUtil.createToolchainContext(
+ env, requiredToolchains, key.getAspectConfiguration());
+ } catch (ToolchainContextException e) {
+ // TODO(katre): better error handling
+ throw new AspectCreationException(e.getMessage());
+ }
+ if (env.valuesMissing()) {
+ return null;
+ }
+
OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap;
try {
- depValueMap = ConfiguredTargetFunction.computeDependencies(
- env,
- resolver,
- originalTargetAndAspectConfiguration,
- aspectPath,
- configConditions,
- ruleClassProvider,
- view.getHostConfiguration(originalTargetAndAspectConfiguration.getConfiguration()),
- transitivePackages,
- transitiveRootCauses);
+ depValueMap =
+ ConfiguredTargetFunction.computeDependencies(
+ env,
+ resolver,
+ originalTargetAndAspectConfiguration,
+ aspectPath,
+ configConditions,
+ toolchainContext,
+ ruleClassProvider,
+ view.getHostConfiguration(originalTargetAndAspectConfiguration.getConfiguration()),
+ transitivePackages,
+ transitiveRootCauses);
} catch (ConfiguredTargetFunctionException e) {
throw new AspectCreationException(e.getMessage());
}
@@ -296,6 +315,7 @@ public final class AspectFunction implements SkyFunction {
associatedTarget,
key.getAspectConfiguration(),
configConditions,
+ toolchainContext,
depValueMap,
transitivePackages);
} catch (DependencyEvaluationException e) {
@@ -419,6 +439,7 @@ public final class AspectFunction implements SkyFunction {
ConfiguredTarget associatedTarget,
BuildConfiguration aspectConfiguration,
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ ToolchainContext toolchainContext,
OrderedSetMultimap<Attribute, ConfiguredTarget> directDeps,
NestedSetBuilder<Package> transitivePackages)
throws AspectFunctionException, InterruptedException {
@@ -434,16 +455,19 @@ public final class AspectFunction implements SkyFunction {
ConfiguredAspect configuredAspect;
if (ConfiguredTargetFunction.aspectMatchesConfiguredTarget(associatedTarget, aspect)) {
- configuredAspect = view.getConfiguredTargetFactory().createAspect(
- analysisEnvironment,
- associatedTarget,
- aspectPath,
- aspectFactory,
- aspect,
- directDeps,
- configConditions,
- aspectConfiguration,
- view.getHostConfiguration(aspectConfiguration));
+ configuredAspect =
+ view.getConfiguredTargetFactory()
+ .createAspect(
+ analysisEnvironment,
+ associatedTarget,
+ aspectPath,
+ aspectFactory,
+ aspect,
+ directDeps,
+ configConditions,
+ toolchainContext,
+ aspectConfiguration,
+ view.getHostConfiguration(aspectConfiguration));
} else {
configuredAspect = ConfiguredAspect.forNonapplicableTarget(aspect.getDescriptor());
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index 27cc52647f..0d11365d45 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -42,6 +42,7 @@ import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget;
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
+import com.google.devtools.build.lib.analysis.ToolchainContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -72,6 +73,8 @@ import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.skyframe.AspectFunction.AspectCreationException;
import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider;
+import com.google.devtools.build.lib.skyframe.ToolchainUtil.ToolchainContextException;
+import com.google.devtools.build.lib.skyframe.ToolchainUtil.UnresolvedToolchainsException;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.util.OrderedSetMultimap;
import com.google.devtools.build.lib.util.Preconditions;
@@ -99,12 +102,12 @@ import javax.annotation.Nullable;
/**
* SkyFunction for {@link ConfiguredTargetValue}s.
*
- * This class, together with {@link AspectFunction} drives the analysis phase. For more information,
- * see {@link com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory}.
+ * <p>This class, together with {@link AspectFunction} drives the analysis phase. For more
+ * information, see {@link com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory}.
*
* @see com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory
*/
-final class ConfiguredTargetFunction implements SkyFunction {
+public final class ConfiguredTargetFunction implements SkyFunction {
// This construction is a bit funky, but guarantees that the Object reference here is globally
// unique.
static final ImmutableMap<Label, ConfigMatchingProvider> NO_CONFIG_CONDITIONS =
@@ -231,6 +234,19 @@ final class ConfiguredTargetFunction implements SkyFunction {
new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
}
+ // Determine what toolchains are needed by this target.
+ ToolchainContext toolchainContext = null;
+ if (target instanceof Rule) {
+ ImmutableList<Label> requiredToolchains =
+ ((Rule) target).getRuleClassObject().getRequiredToolchains();
+ toolchainContext =
+ ToolchainUtil.createToolchainContext(env, requiredToolchains, configuration);
+ if (env.valuesMissing()) {
+ return null;
+ }
+ }
+
+ // Calculate the dependencies of this target.
OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap =
computeDependencies(
env,
@@ -238,6 +254,7 @@ final class ConfiguredTargetFunction implements SkyFunction {
ctgValue,
ImmutableList.<Aspect>of(),
configConditions,
+ toolchainContext,
ruleClassProvider,
view.getHostConfiguration(configuration),
transitivePackages,
@@ -250,8 +267,16 @@ final class ConfiguredTargetFunction implements SkyFunction {
new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
}
Preconditions.checkNotNull(depValueMap);
- ConfiguredTargetValue ans = createConfiguredTarget(
- view, env, target, configuration, depValueMap, configConditions, transitivePackages);
+ ConfiguredTargetValue ans =
+ createConfiguredTarget(
+ view,
+ env,
+ target,
+ configuration,
+ depValueMap,
+ configConditions,
+ toolchainContext,
+ transitivePackages);
return ans;
} catch (DependencyEvaluationException e) {
if (e.getCause() instanceof ConfiguredValueCreationException) {
@@ -276,28 +301,45 @@ final class ConfiguredTargetFunction implements SkyFunction {
}
throw new ConfiguredTargetFunctionException(
new ConfiguredValueCreationException(e.getMessage(), analysisRootCause));
+ } catch (ToolchainContextException e) {
+ if (e.getCause() instanceof UnresolvedToolchainsException) {
+ UnresolvedToolchainsException ute = (UnresolvedToolchainsException) e.getCause();
+ env.getListener()
+ .handle(Event.error(ute.getMessage() + " for target " + target.getLabel()));
+ throw new ConfiguredTargetFunctionException(
+ new ConfiguredValueCreationException(ute.getMessage(), target.getLabel()));
+ } else if (e.getCause() instanceof ConfiguredValueCreationException) {
+ ConfiguredValueCreationException cvce = (ConfiguredValueCreationException) e.getCause();
+ throw new ConfiguredTargetFunctionException(cvce);
+ } else {
+ // TODO(katre): better error handling
+ throw new ConfiguredTargetFunctionException(
+ new ConfiguredValueCreationException(e.getMessage()));
+ }
} finally {
cpuBoundSemaphore.release();
}
}
/**
- * Computes the direct dependencies of a node in the configured target graph (a configured
- * target or an aspects).
+ * Computes the direct dependencies of a node in the configured target graph (a configured target
+ * or an aspects).
*
* <p>Returns null if Skyframe hasn't evaluated the required dependencies yet. In this case, the
* caller should also return null to Skyframe.
- * @param env the Skyframe environment
+ *
+ * @param env the Skyframe environment
* @param resolver the dependency resolver
* @param ctgValue the label and the configuration of the node
* @param aspects
* @param configConditions the configuration conditions for evaluating the attributes of the node
+ * @param toolchainContext context information for required toolchains
* @param ruleClassProvider rule class provider for determining the right configuration fragments
- * to apply to deps
+ * to apply to deps
* @param hostConfiguration the host configuration. There's a noticeable performance hit from
* instantiating this on demand for every dependency that wants it, so it's best to compute
* the host configuration as early as possible and pass this reference to all consumers
- * */
+ */
@Nullable
static OrderedSetMultimap<Attribute, ConfiguredTarget> computeDependencies(
Environment env,
@@ -305,17 +347,24 @@ final class ConfiguredTargetFunction implements SkyFunction {
TargetAndConfiguration ctgValue,
Iterable<Aspect> aspects,
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ @Nullable ToolchainContext toolchainContext,
RuleClassProvider ruleClassProvider,
BuildConfiguration hostConfiguration,
NestedSetBuilder<Package> transitivePackages,
NestedSetBuilder<Label> transitiveLoadingRootCauses)
throws DependencyEvaluationException, ConfiguredTargetFunctionException,
- AspectCreationException, InterruptedException {
+ AspectCreationException, InterruptedException {
// Create the map from attributes to set of (target, configuration) pairs.
OrderedSetMultimap<Attribute, Dependency> depValueNames;
try {
- depValueNames = resolver.dependentNodeMap(
- ctgValue, hostConfiguration, aspects, configConditions, transitiveLoadingRootCauses);
+ depValueNames =
+ resolver.dependentNodeMap(
+ ctgValue,
+ hostConfiguration,
+ aspects,
+ configConditions,
+ toolchainContext,
+ transitiveLoadingRootCauses);
} catch (EvalException e) {
// EvalException can only be thrown by computed Skylark attributes in the current rule.
env.getListener().handle(Event.error(e.getLocation(), e.getMessage()));
@@ -1102,10 +1151,14 @@ final class ConfiguredTargetFunction implements SkyFunction {
}
@Nullable
- private ConfiguredTargetValue createConfiguredTarget(SkyframeBuildView view,
- Environment env, Target target, BuildConfiguration configuration,
+ private ConfiguredTargetValue createConfiguredTarget(
+ SkyframeBuildView view,
+ Environment env,
+ Target target,
+ BuildConfiguration configuration,
OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap,
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ @Nullable ToolchainContext toolchainContext,
NestedSetBuilder<Package> transitivePackages)
throws ConfiguredTargetFunctionException, InterruptedException {
StoredEventHandler events = new StoredEventHandler();
@@ -1122,8 +1175,14 @@ final class ConfiguredTargetFunction implements SkyFunction {
}
Preconditions.checkNotNull(depValueMap);
- ConfiguredTarget configuredTarget = view.createConfiguredTarget(target, configuration,
- analysisEnvironment, depValueMap, configConditions);
+ ConfiguredTarget configuredTarget =
+ view.createConfiguredTarget(
+ target,
+ configuration,
+ analysisEnvironment,
+ depValueMap,
+ configConditions,
+ toolchainContext);
events.replayOn(env.getListener());
if (events.hasErrors()) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
index 14a96e5120..4f1d96eaef 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
@@ -38,6 +38,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.ConfiguredTargetFactory;
import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
+import com.google.devtools.build.lib.analysis.ToolchainContext;
import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory;
import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoKey;
@@ -477,18 +478,28 @@ public final class SkyframeBuildView {
* <p>Returns null if Skyframe deps are missing or upon certain errors.
*/
@Nullable
- ConfiguredTarget createConfiguredTarget(Target target, BuildConfiguration configuration,
+ ConfiguredTarget createConfiguredTarget(
+ Target target,
+ BuildConfiguration configuration,
CachingAnalysisEnvironment analysisEnvironment,
OrderedSetMultimap<Attribute, ConfiguredTarget> prerequisiteMap,
- ImmutableMap<Label, ConfigMatchingProvider> configConditions) throws InterruptedException {
+ ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+ @Nullable ToolchainContext toolchainContext)
+ throws InterruptedException {
Preconditions.checkState(enableAnalysis,
"Already in execution phase %s %s", target, configuration);
Preconditions.checkNotNull(analysisEnvironment);
Preconditions.checkNotNull(target);
Preconditions.checkNotNull(prerequisiteMap);
- return factory.createConfiguredTarget(analysisEnvironment, artifactFactory, target,
- configuration, getHostConfiguration(configuration), prerequisiteMap,
- configConditions);
+ return factory.createConfiguredTarget(
+ analysisEnvironment,
+ artifactFactory,
+ target,
+ configuration,
+ getHostConfiguration(configuration),
+ prerequisiteMap,
+ configConditions,
+ toolchainContext);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java
new file mode 100644
index 0000000000..3afe90af6c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java
@@ -0,0 +1,220 @@
+// Copyright 2017 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.skyframe;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.PlatformConfiguration;
+import com.google.devtools.build.lib.analysis.ToolchainContext;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
+import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.ConfiguredValueCreationException;
+import com.google.devtools.build.lib.skyframe.RegisteredToolchainsFunction.InvalidTargetException;
+import com.google.devtools.build.lib.skyframe.ToolchainResolutionFunction.NoToolchainFoundException;
+import com.google.devtools.build.lib.skyframe.ToolchainResolutionValue.ToolchainResolutionKey;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.skyframe.LegacySkyKey;
+import com.google.devtools.build.skyframe.SkyFunction.Environment;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.ValueOrException;
+import com.google.devtools.build.skyframe.ValueOrException4;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Common code to create a {@link ToolchainContext} given a set of required toolchain type labels.
+ */
+public class ToolchainUtil {
+
+ /**
+ * Returns a new {@link ToolchainContext}, with the correct toolchain labels based on the results
+ * of the {@link ToolchainResolutionFunction}.
+ */
+ public static ToolchainContext createToolchainContext(
+ Environment env, List<Label> requiredToolchains, BuildConfiguration configuration)
+ throws ToolchainContextException, InterruptedException {
+ ImmutableBiMap<Label, Label> resolvedLabels =
+ resolveToolchainLabels(env, requiredToolchains, configuration);
+ ToolchainContext toolchainContext = ToolchainContext.create(requiredToolchains, resolvedLabels);
+ return toolchainContext;
+ }
+
+ /**
+ * Data class to hold platform descriptors loaded based on the current {@link BuildConfiguration}.
+ */
+ @AutoValue
+ protected abstract static class PlatformDescriptors {
+ abstract PlatformInfo execPlatform();
+
+ abstract PlatformInfo targetPlatform();
+
+ protected static PlatformDescriptors create(
+ PlatformInfo execPlatform, PlatformInfo targetPlatform) {
+ return new AutoValue_ToolchainUtil_PlatformDescriptors(execPlatform, targetPlatform);
+ }
+ }
+
+ private static PlatformDescriptors loadPlatformDescriptors(
+ Environment env, BuildConfiguration configuration)
+ throws InterruptedException, ToolchainContextException {
+ PlatformConfiguration platformConfiguration =
+ configuration.getFragment(PlatformConfiguration.class);
+ Label executionPlatformLabel = platformConfiguration.getExecutionPlatform();
+ Label targetPlatformLabel = platformConfiguration.getTargetPlatforms().get(0);
+
+ SkyKey executionPlatformKey =
+ LegacySkyKey.create(
+ SkyFunctions.CONFIGURED_TARGET,
+ new ConfiguredTargetKey(executionPlatformLabel, configuration));
+ SkyKey targetPlatformKey =
+ LegacySkyKey.create(
+ SkyFunctions.CONFIGURED_TARGET,
+ new ConfiguredTargetKey(targetPlatformLabel, configuration));
+
+ Map<SkyKey, ValueOrException<ConfiguredValueCreationException>> values =
+ env.getValuesOrThrow(
+ ImmutableList.of(executionPlatformKey, targetPlatformKey),
+ ConfiguredValueCreationException.class);
+ if (env.valuesMissing()) {
+ return null;
+ }
+ try {
+ ConfiguredTarget executionPlatformTarget =
+ ((ConfiguredTargetValue) values.get(executionPlatformKey).get()).getConfiguredTarget();
+ ConfiguredTarget targetPlatformTarget =
+ ((ConfiguredTargetValue) values.get(targetPlatformKey).get()).getConfiguredTarget();
+ PlatformInfo execPlatform = PlatformProviderUtils.platform(executionPlatformTarget);
+ PlatformInfo targetPlatform = PlatformProviderUtils.platform(targetPlatformTarget);
+
+ return PlatformDescriptors.create(execPlatform, targetPlatform);
+ } catch (ConfiguredValueCreationException e) {
+ throw new ToolchainContextException(e);
+ }
+ }
+
+ private static ImmutableBiMap<Label, Label> resolveToolchainLabels(
+ Environment env, List<Label> requiredToolchains, BuildConfiguration configuration)
+ throws InterruptedException, ToolchainContextException {
+
+ // If there are no required toolchains, bail out early.
+ if (requiredToolchains.isEmpty()) {
+ return ImmutableBiMap.of();
+ }
+
+ // Load the execution and target platforms for the current configuration.
+ PlatformDescriptors platforms = loadPlatformDescriptors(env, configuration);
+ if (platforms == null) {
+ return null;
+ }
+
+ // Find the toolchains for the required toolchain types.
+ List<SkyKey> registeredToolchainKeys = new ArrayList<>();
+ for (Label toolchainType : requiredToolchains) {
+ registeredToolchainKeys.add(
+ ToolchainResolutionValue.key(
+ configuration, toolchainType, platforms.targetPlatform(), platforms.execPlatform()));
+ }
+
+ Map<
+ SkyKey,
+ ValueOrException4<
+ NoToolchainFoundException, ConfiguredValueCreationException, InvalidTargetException,
+ EvalException>>
+ results =
+ env.getValuesOrThrow(
+ registeredToolchainKeys,
+ NoToolchainFoundException.class,
+ ConfiguredValueCreationException.class,
+ InvalidTargetException.class,
+ EvalException.class);
+ if (env.valuesMissing()) {
+ return null;
+ }
+
+ // Load the toolchains.
+ ImmutableBiMap.Builder<Label, Label> builder = new ImmutableBiMap.Builder<>();
+ List<Label> missingToolchains = new ArrayList<>();
+ for (Map.Entry<
+ SkyKey,
+ ValueOrException4<
+ NoToolchainFoundException, ConfiguredValueCreationException, InvalidTargetException,
+ EvalException>>
+ entry : results.entrySet()) {
+ try {
+ Label requiredToolchainType =
+ ((ToolchainResolutionKey) entry.getKey().argument()).toolchainType();
+ Label toolchainLabel = ((ToolchainResolutionValue) entry.getValue().get()).toolchainLabel();
+ builder.put(requiredToolchainType, toolchainLabel);
+ } catch (NoToolchainFoundException e) {
+ // Save the missing type and continue looping to check for more.
+ missingToolchains.add(e.missingToolchainType());
+ } catch (ConfiguredValueCreationException e) {
+ throw new ToolchainContextException(e);
+ } catch (InvalidTargetException e) {
+ throw new ToolchainContextException(e);
+ } catch (EvalException e) {
+ throw new ToolchainContextException(e);
+ }
+ }
+
+ if (!missingToolchains.isEmpty()) {
+ throw new ToolchainContextException(new UnresolvedToolchainsException(missingToolchains));
+ }
+
+ return builder.build();
+ }
+
+ /** Exception used when a toolchain type is required but no matching toolchain is found. */
+ public static final class UnresolvedToolchainsException extends Exception {
+ private final ImmutableList<Label> missingToolchainTypes;
+
+ public UnresolvedToolchainsException(List<Label> missingToolchainTypes) {
+ super(
+ String.format(
+ "no matching toolchains found for types %s",
+ Joiner.on(", ").join(missingToolchainTypes)));
+ this.missingToolchainTypes = ImmutableList.copyOf(missingToolchainTypes);
+ }
+
+ public ImmutableList<Label> missingToolchainTypes() {
+ return missingToolchainTypes;
+ }
+ }
+
+ /** Exception used to wrap exceptions during toolchain resolution. */
+ public static class ToolchainContextException extends Exception {
+ public ToolchainContextException(UnresolvedToolchainsException e) {
+ super(e);
+ }
+
+ public ToolchainContextException(ConfiguredValueCreationException e) {
+ super(e);
+ }
+
+ public ToolchainContextException(InvalidTargetException e) {
+ super(e);
+ }
+
+ public ToolchainContextException(EvalException e) {
+ super(e);
+ }
+ }
+}