diff options
author | Greg Estren <gregce@google.com> | 2016-08-09 22:36:51 +0000 |
---|---|---|
committer | Yue Gan <yueg@google.com> | 2016-08-10 08:38:45 +0000 |
commit | 373e3e28274cca5b87f48abe33884edb84016dd3 (patch) | |
tree | 61744785eadf07f70d0a9a3264c00cf992441190 /src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java | |
parent | eff8b365c172b7e904ac6f7bba0c893fed7c91a8 (diff) |
Implements dynamic split transitions on latebound attributes.
With this change, dynamic configs are at full feature parity for
split transitions (minus some small differences in composed
transitions from BuildConfigurationCollection.configurationHook).
--
MOS_MIGRATED_REVID=129802414
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java | 91 |
1 files changed, 77 insertions, 14 deletions
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 66360f4828..3956037516 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,7 +22,10 @@ import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; 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.InvalidConfigurationException; +import com.google.devtools.build.lib.analysis.config.PatchTransition; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.Aspect; @@ -94,7 +97,7 @@ public abstract class DependencyResolver { BuildConfiguration hostConfig, @Nullable Aspect aspect, ImmutableMap<Label, ConfigMatchingProvider> configConditions) - throws EvalException, InterruptedException { + throws EvalException, InvalidConfigurationException, InterruptedException { NestedSetBuilder<Label> rootCauses = NestedSetBuilder.<Label>stableOrder(); ListMultimap<Attribute, Dependency> outgoingEdges = dependentNodeMap( node, hostConfig, aspect, configConditions, rootCauses); @@ -138,7 +141,7 @@ public abstract class DependencyResolver { @Nullable Aspect aspect, ImmutableMap<Label, ConfigMatchingProvider> configConditions, NestedSetBuilder<Label> rootCauses) - throws EvalException, InterruptedException { + throws EvalException, InvalidConfigurationException, InterruptedException { Target target = node.getTarget(); BuildConfiguration config = node.getConfiguration(); ListMultimap<Attribute, Dependency> outgoingEdges = ArrayListMultimap.create(); @@ -168,7 +171,7 @@ public abstract class DependencyResolver { ImmutableMap<Label, ConfigMatchingProvider> configConditions, NestedSetBuilder<Label> rootCauses, ListMultimap<Attribute, Dependency> outgoingEdges) - throws EvalException, InterruptedException { + throws EvalException, InvalidConfigurationException, InterruptedException { Preconditions.checkArgument(node.getTarget() instanceof Rule); BuildConfiguration ruleConfig = Preconditions.checkNotNull(node.getConfiguration()); Rule rule = (Rule) node.getTarget(); @@ -316,7 +319,7 @@ public abstract class DependencyResolver { RuleResolver depResolver, BuildConfiguration ruleConfig, BuildConfiguration hostConfig) - throws EvalException, InterruptedException { + throws EvalException, InvalidConfigurationException, InterruptedException { ConfiguredAttributeMapper attributeMap = depResolver.attributeMap; for (Attribute attribute : depResolver.attributes) { if (!attribute.isLateBound() || !attribute.getCondition().apply(attributeMap)) { @@ -327,7 +330,9 @@ public abstract class DependencyResolver { LateBoundDefault<BuildConfiguration> lateBoundDefault = (LateBoundDefault<BuildConfiguration>) attribute.getLateBoundDefault(); - if (attribute.hasSplitConfigurationTransition()) { + Collection<BuildOptions> splitOptions = + getSplitOptions(depResolver.rule, attribute, ruleConfig); + if (!splitOptions.isEmpty()) { // Late-bound attribute with a split transition: // Since we want to get the same results as BuildConfiguration.evaluateTransition (but // skip it since we've already applied the split), we want to make sure this logic @@ -336,9 +341,18 @@ public abstract class DependencyResolver { // of those apply, in the name of keeping the fork as simple as possible. Verify.verify(attribute.getConfigurator() == null); Verify.verify(!lateBoundDefault.useHostConfiguration()); - for (BuildConfiguration splitConfig : ruleConfig.getSplitConfigurations( - attribute.getSplitTransition(depResolver.rule))) { - // TODO(gregce): support dynamic split transitions + + Iterable<BuildConfiguration> splitConfigs; + if (!ruleConfig.useDynamicConfigurations()) { + splitConfigs = ruleConfig + .getSplitConfigurations(attribute.getSplitTransition(depResolver.rule)); + } else { + splitConfigs = getConfigurations(ruleConfig.fragmentClasses(), splitOptions); + if (splitConfigs == null) { + continue; // Need Skyframe deps. + } + } + for (BuildConfiguration splitConfig : splitConfigs) { for (Label dep : resolveLateBoundAttribute( depResolver.rule, attribute, splitConfig, attributeMap)) { // Skip the normal config transition pipeline and directly feed the split config. This @@ -360,6 +374,23 @@ public abstract class DependencyResolver { } /** + * Returns true if the rule's attribute triggers a split in this configuration. + * + * <p>Even though the attribute may have a split, splits don't have to apply in every + * configuration (see {@link Attribute.SplitTransition#split}). + */ + private static Collection<BuildOptions> getSplitOptions(Rule rule, Attribute attribute, + BuildConfiguration ruleConfig) { + if (!attribute.hasSplitConfigurationTransition()) { + return ImmutableList.<BuildOptions>of(); + } + @SuppressWarnings("unchecked") // Attribute.java doesn't have the BuildOptions symbol. + Attribute.SplitTransition<BuildOptions> transition = + (Attribute.SplitTransition<BuildOptions>) attribute.getSplitTransition(rule); + return transition.split(ruleConfig.getOptions()); + } + + /** * Returns the label dependencies for the given late-bound attribute in this rule. * * @param rule the rule being evaluated @@ -586,8 +617,6 @@ public abstract class DependencyResolver { * configurations to apply to it. */ void resolveDep(Attribute attribute, Label depLabel) { - // Late-bound split attributes are separately handled (see LateBoundSplitResolver). - Verify.verify(!(attribute.isLateBound() && attribute.hasSplitConfigurationTransition())); Target toTarget = getTarget(rule, depLabel, rootCauses); if (toTarget == null) { return; // Skip this round: we still need to Skyframe-evaluate the dep's target. @@ -625,10 +654,9 @@ public abstract class DependencyResolver { ImmutableSet<AspectDescriptor> aspects = requiredAspects(aspect, attribute, toTarget, rule); Dependency dep; if (config.useDynamicConfigurations() && !applyNullTransition) { - // Since we feed a pre-prepared configuration directly to the dep, it won't get trimmed to - // the dep's fragments. - // TODO(gregce): properly trim this configuration, too. - dep = Dependency.withConfigurationAndAspects(depLabel, config, aspects); + // Pass a transition rather than directly feeding the configuration so deps get trimmed. + dep = Dependency.withTransitionAndAspects( + depLabel, new FixedTransition(config.getOptions()), aspects); } else { dep = Iterables.getOnlyElement(transitionApplier.getDependencies(depLabel, aspects)); } @@ -637,6 +665,27 @@ public abstract class DependencyResolver { } } + /** + * A patch transition that returns a fixed set of options regardless of the input. + */ + private static class FixedTransition implements PatchTransition { + private final BuildOptions toOptions; + + FixedTransition(BuildOptions toOptions) { + this.toOptions = toOptions; + } + + @Override + public BuildOptions apply(BuildOptions options) { + return toOptions; + } + + @Override + public boolean defaultsToSelf() { + return false; + } + } + private void visitTargetVisibility(TargetAndConfiguration node, NestedSetBuilder<Label> rootCauses, Collection<Dependency> outgoingEdges) { Target target = node.getTarget(); @@ -696,4 +745,18 @@ public abstract class DependencyResolver { */ @Nullable protected abstract Target getTarget(Target from, Label label, NestedSetBuilder<Label> rootCauses); + + /** + * Returns the build configurations with the given options and fragments, in the same order as + * the input options. + * + * <p>Returns null if any configurations aren't ready to be returned at this moment. If + * getConfigurations returns null once or more during a {@link #dependentNodeMap} call, the + * results of that call will be incomplete. For use within Skyframe, where several iterations may + * be needed to discover all dependencies. + */ + @Nullable + protected abstract List<BuildConfiguration> getConfigurations( + Set<Class<? extends BuildConfiguration.Fragment>> fragments, + Iterable<BuildOptions> buildOptions) throws InvalidConfigurationException; } |