diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java | 73 |
1 files changed, 68 insertions, 5 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java index 1e02ef38c5..ae5ca36550 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java @@ -14,8 +14,12 @@ package com.google.devtools.build.lib.skyframe; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; +import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.events.Event; @@ -31,6 +35,7 @@ import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.PackageGroup; import com.google.devtools.build.lib.packages.PackageIdentifier; import com.google.devtools.build.lib.packages.Rule; +import com.google.devtools.build.lib.packages.RuleClassProvider; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.syntax.Label; @@ -42,6 +47,7 @@ import com.google.devtools.build.skyframe.ValueOrException; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map.Entry; import java.util.Set; @@ -52,6 +58,12 @@ import java.util.Set; */ public class TransitiveTargetFunction implements SkyFunction { + private final ConfiguredRuleClassProvider ruleClassProvider; + + TransitiveTargetFunction(RuleClassProvider ruleClassProvider) { + this.ruleClassProvider = (ConfiguredRuleClassProvider) ruleClassProvider; + } + @Override public SkyValue compute(SkyKey key, Environment env) throws TransitiveTargetFunctionException { Label label = (Label) key.argument(); @@ -119,6 +131,11 @@ public class TransitiveTargetFunction implements SkyFunction { NestedSetBuilder<PackageIdentifier> transitiveSuccessfulPkgs = NestedSetBuilder.stableOrder(); NestedSetBuilder<PackageIdentifier> transitiveUnsuccessfulPkgs = NestedSetBuilder.stableOrder(); NestedSetBuilder<Label> transitiveTargets = NestedSetBuilder.stableOrder(); + NestedSetBuilder<Class<? extends BuildConfiguration.Fragment>> transitiveConfigFragments = + NestedSetBuilder.stableOrder(); + // No need to store directly required fragments that are also required by deps. + Set<Class<? extends BuildConfiguration.Fragment>> configFragmentsFromDeps = + new LinkedHashSet<>(); PackageIdentifier packageId = target.getPackage().getPackageIdentifier(); if (packageLoadedSuccessfully) { @@ -131,36 +148,67 @@ public class TransitiveTargetFunction implements SkyFunction { // Process deps from attributes of current target. Iterable<SkyKey> depKeys = getLabelDepKeys(target); successfulTransitiveLoading &= processDeps(env, target, transitiveRootCauses, - transitiveSuccessfulPkgs, transitiveUnsuccessfulPkgs, transitiveTargets, depKeys); + transitiveSuccessfulPkgs, transitiveUnsuccessfulPkgs, transitiveTargets, depKeys, + transitiveConfigFragments, configFragmentsFromDeps); if (env.valuesMissing()) { return null; } // Process deps from aspects. depKeys = getLabelAspectKeys(target, env); successfulTransitiveLoading &= processDeps(env, target, transitiveRootCauses, - transitiveSuccessfulPkgs, transitiveUnsuccessfulPkgs, transitiveTargets, depKeys); + transitiveSuccessfulPkgs, transitiveUnsuccessfulPkgs, transitiveTargets, depKeys, + transitiveConfigFragments, configFragmentsFromDeps); if (env.valuesMissing()) { return null; } + // Get configuration fragments directly required by this target. + if (target instanceof Rule) { + Set<Class<?>> configFragments = + target.getAssociatedRule().getRuleClassObject().getRequiredConfigurationFragments(); + // An empty result means this rule requires all fragments (which practically means + // the rule isn't yet declaring its actually needed fragments). So load everything. + configFragments = configFragments.isEmpty() ? getAllFragments() : configFragments; + for (Class<?> fragment : configFragments) { + if (!configFragmentsFromDeps.contains(fragment)) { + transitiveConfigFragments.add((Class<? extends BuildConfiguration.Fragment>) fragment); + } + } + } + NestedSet<PackageIdentifier> successfullyLoadedPackages = transitiveSuccessfulPkgs.build(); NestedSet<PackageIdentifier> unsuccessfullyLoadedPackages = transitiveUnsuccessfulPkgs.build(); NestedSet<Label> loadedTargets = transitiveTargets.build(); if (successfulTransitiveLoading) { return TransitiveTargetValue.successfulTransitiveLoading(successfullyLoadedPackages, - unsuccessfullyLoadedPackages, loadedTargets); + unsuccessfullyLoadedPackages, loadedTargets, transitiveConfigFragments.build()); } else { NestedSet<Label> rootCauses = transitiveRootCauses.build(); return TransitiveTargetValue.unsuccessfulTransitiveLoading(successfullyLoadedPackages, - unsuccessfullyLoadedPackages, loadedTargets, rootCauses, errorLoadingTarget); + unsuccessfullyLoadedPackages, loadedTargets, rootCauses, errorLoadingTarget, + transitiveConfigFragments.build()); } } + /** + * Returns every configuration fragment known to the system. + */ + private Set<Class<?>> getAllFragments() { + ImmutableSet.Builder<Class<?>> builder = + ImmutableSet.builder(); + for (ConfigurationFragmentFactory factory : ruleClassProvider.getConfigurationFragments()) { + builder.add(factory.creates()); + } + return builder.build(); + } + private boolean processDeps(Environment env, Target target, NestedSetBuilder<Label> transitiveRootCauses, NestedSetBuilder<PackageIdentifier> transitiveSuccessfulPkgs, NestedSetBuilder<PackageIdentifier> transitiveUnsuccessfulPkgs, - NestedSetBuilder<Label> transitiveTargets, Iterable<SkyKey> depKeys) { + NestedSetBuilder<Label> transitiveTargets, Iterable<SkyKey> depKeys, + NestedSetBuilder<Class<? extends BuildConfiguration.Fragment>> transitiveConfigFragments, + Set<Class<? extends BuildConfiguration.Fragment>> addedConfigFragments) { boolean successfulTransitiveLoading = true; for (Entry<SkyKey, ValueOrException<NoSuchThingException>> entry : env.getValuesOrThrow(depKeys, NoSuchThingException.class).entrySet()) { @@ -193,6 +241,21 @@ public class TransitiveTargetFunction implements SkyFunction { transitiveTargetValue.getErrorLoadingTarget(), env.getListener()); } } + + NestedSet<Class<? extends BuildConfiguration.Fragment>> depFragments = + transitiveTargetValue.getTransitiveConfigFragments(); + Collection<Class<? extends BuildConfiguration.Fragment>> depFragmentsAsCollection = + depFragments.toCollection(); + // The simplest collection technique would be to unconditionally add all deps' nested + // sets to the current target's nested set. But when there's large overlap between their + // fragment needs, this produces unnecessarily bloated nested sets and a lot of references + // that don't contribute anything unique to the required fragment set. So we optimize here + // by completely skipping sets that don't offer anything new. More fine-tuned optimization + // is possible, but this offers a good balance between simplicity and practical efficiency. + if (!addedConfigFragments.containsAll(depFragmentsAsCollection)) { + transitiveConfigFragments.addTransitive(depFragments); + addedConfigFragments.addAll(depFragmentsAsCollection); + } } return successfulTransitiveLoading; } |