blob: 207d2ae7b58bd3bd0f75ab46926ed82d113cd9b1 [file] [log] [blame]
// 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.analysis.config;
import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition;
import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
import com.google.devtools.build.lib.analysis.config.transitions.NullTransition;
import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.Target;
import javax.annotation.Nullable;
/**
* Tool for evaluating which {@link ConfigurationTransition}(s) should be applied to given targets.
*
* <p>For the work of turning these transitions into actual configurations, see {@link
* ConfigurationResolver}.
*
* <p>This is the "generic engine" for configuration selection. It doesn't know anything about
* specific rules or their requirements. Rule writers decide those with appropriately placed {@link
* PatchTransition} declarations. This class then processes those declarations to determine final
* transitions.
*/
public final class TransitionResolver {
/**
* Given an original configuration and a base transition, determines the configuration a target
* should have.
*
* @param fromConfig the original configuration
* @param baseTransition the base configuration transitions computed by this method should be
* composed with (the configuration transition of the attribute through which this dependency
* happens or {@code NoTransition.INSTANCE} if this is a top-level target)
* @param toTarget the target whose configuration should be computed (may or may not be a rule)
* @param trimmingTransitionFactory the transition factory used to trim rules (note: this is a
* temporary feature; see the corresponding methods in {@code ConfiguredRuleClassProvider})
* @return the target's configuration(s), expressed as a diff from the original configuration.
*/
public static ConfigurationTransition evaluateTransition(
BuildConfiguration fromConfig,
ConfigurationTransition baseTransition,
Target toTarget,
@Nullable TransitionFactory<Rule> trimmingTransitionFactory) {
// I. The null configuration always remains the null configuration. We could fold this into
// (III), but NoTransition doesn't work if the source is the null configuration.
if (fromConfig == null) {
return NullTransition.INSTANCE;
}
// II. Input files and package groups have no configurations. We don't want to duplicate them.
if (!toTarget.isConfigurable()) {
return NullTransition.INSTANCE;
}
// III. Host configurations never switch to another. All prerequisites of host targets have the
// same host configuration.
if (fromConfig.isHostConfiguration()) {
return NoTransition.INSTANCE;
}
// The current transition to apply. When multiple transitions are requested, this is a
// ComposingTransition, which encapsulates them into a single object so calling code
// doesn't need special logic for combinations.
// IV. Apply whatever transition the attribute requires.
ConfigurationTransition currentTransition = baseTransition;
// V. Applies any rule transitions associated with the dep target and composes their
// transitions with a passed-in existing transition.
currentTransition = applyRuleTransition(currentTransition, toTarget);
// VI. Applies a transition to trim the result and returns it. (note: this is a temporary
// feature; see the corresponding methods in ConfiguredRuleClassProvider)
return applyTransitionFromFactory(currentTransition, toTarget, trimmingTransitionFactory);
}
/**
* @param currentTransition a pre-existing transition to be composed with
* @param toTarget target whose associated rule's incoming transition should be applied
*/
private static ConfigurationTransition applyRuleTransition(
ConfigurationTransition currentTransition, Target toTarget) {
Rule associatedRule = toTarget.getAssociatedRule();
TransitionFactory<Rule> transitionFactory =
associatedRule.getRuleClassObject().getTransitionFactory();
return applyTransitionFromFactory(currentTransition, toTarget, transitionFactory);
}
/**
* @param currentTransition a pre-existing transition to be composed with
* @param toTarget target whose associated rule's incoming transition should be applied
* @param transitionFactory a rule transition factory to apply, or null to do nothing
*/
private static ConfigurationTransition applyTransitionFromFactory(
ConfigurationTransition currentTransition,
Target toTarget,
@Nullable TransitionFactory<Rule> transitionFactory) {
if (transitionFactory != null) {
return ComposingTransition.of(
currentTransition, transitionFactory.create(toTarget.getAssociatedRule()));
}
return currentTransition;
}
}