aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java
diff options
context:
space:
mode:
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.java73
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;
}