From 2e56f0664d91fce3974938198d8a30e1aeef8d62 Mon Sep 17 00:00:00 2001 From: John Cater Date: Thu, 20 Jul 2017 19:43:20 +0200 Subject: Use toolchain resolution in rule creation. Part of #2219. Change-Id: Id4929d5ddcd57b4635af5e513eb9a09f16a78e71 PiperOrigin-RevId: 162634398 --- .../lib/analysis/ConfiguredTargetFactory.java | 54 +++-- .../build/lib/analysis/DependencyResolver.java | 58 ++++-- .../build/lib/analysis/PlatformSemantics.java | 27 +-- .../build/lib/analysis/ToolchainContext.java | 183 +++++++++++++++-- .../build/lib/rules/SkylarkRuleContext.java | 17 +- .../build/lib/skyframe/AspectFunction.java | 64 ++++-- .../lib/skyframe/ConfiguredTargetFunction.java | 93 +++++++-- .../build/lib/skyframe/SkyframeBuildView.java | 21 +- .../devtools/build/lib/skyframe/ToolchainUtil.java | 220 +++++++++++++++++++++ 9 files changed, 615 insertions(+), 122 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java (limited to 'src/main/java/com/google/devtools') 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. + * *

For use in {@code ConfiguredTargetFunction}. * *

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 prerequisiteMap, - ImmutableMap configConditions) + ImmutableMap 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 prerequisiteMap, - ImmutableMap configConditions) throws InterruptedException { + ImmutableMap 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 prerequisiteMap, ImmutableMap 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 configConditions) throws EvalException, InvalidConfigurationException, InterruptedException, - InconsistentAspectOrderException { + InconsistentAspectOrderException { NestedSetBuilder

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. + *

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. * - *

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}. + *

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}. * *

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 dependentNodeMap( TargetAndConfiguration node, BuildConfiguration hostConfig, Iterable aspects, ImmutableMap configConditions, + @Nullable ToolchainContext toolchainContext, NestedSetBuilder

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 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

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 computeDependencies( Environment env, @@ -305,17 +347,24 @@ final class ConfiguredTargetFunction implements SkyFunction { TargetAndConfiguration ctgValue, Iterable aspects, ImmutableMap configConditions, + @Nullable ToolchainContext toolchainContext, RuleClassProvider ruleClassProvider, BuildConfiguration hostConfiguration, NestedSetBuilder transitivePackages, NestedSetBuilder

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 prerequisiteMap, - ImmutableMap configConditions) throws InterruptedException { + ImmutableMap 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