aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build
diff options
context:
space:
mode:
authorGravatar Greg Estren <gregce@google.com>2015-05-26 22:37:44 +0000
committerGravatar Laurent Le Brun <laurentlb@google.com>2015-05-27 16:46:09 +0000
commit531fc042bba338613978cf65d86a6299859f5e1e (patch)
treedd383164063fde81bf1e6a6135c32f5cf406385e /src/main/java/com/google/devtools/build
parentb46c6351321c2950badb4c0e4071e3f20d49e338 (diff)
Add an entry to TransitiveTargetValue that tracks the
configuration fragments needed by a rule's transitive closure. Also add a Skyframe BuildConfiguration node. Memory and performance profiling shows no noticeable performance hit in loading or analysis and a 0.35% memory increase for moderately sized (by Google standards) build graphs when these are depended upon in ConfiguredTargetFunction. -- MOS_MIGRATED_REVID=94517099
Diffstat (limited to 'src/main/java/com/google/devtools/build')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java102
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java113
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java73
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetValue.java42
7 files changed, 329 insertions, 14 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index 0c53af0e15..267b8d32de 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -993,7 +993,7 @@ public final class BuildConfiguration implements Serializable {
return builder.build();
}
- BuildConfiguration(BlazeDirectories directories,
+ public BuildConfiguration(BlazeDirectories directories,
Map<Class<? extends Fragment>, Fragment> fragmentsMap,
BuildOptions buildOptions,
boolean actionsDisabled) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java
new file mode 100644
index 0000000000..3de1bc5c09
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java
@@ -0,0 +1,102 @@
+// Copyright 2015 Google Inc. 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 static com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
+
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.MutableClassToInstanceMap;
+import com.google.devtools.build.lib.analysis.BlazeDirectories;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+import com.google.devtools.build.skyframe.ValueOrException;
+
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A builder for {@link BuildConfigurationValue} instances.
+ */
+public class BuildConfigurationFunction implements SkyFunction {
+
+ private final BlazeDirectories directories;
+
+ public BuildConfigurationFunction(BlazeDirectories directories) {
+ this.directories = directories;
+ }
+
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws InterruptedException,
+ SkyFunctionException {
+ BuildConfigurationValue.Key key = (BuildConfigurationValue.Key) skyKey.argument();
+ Set<Fragment> fragments;
+ try {
+ fragments = getConfigurationFragments(key, env);
+ } catch (InvalidConfigurationException e) {
+ throw new BuildConfigurationFunctionException(e);
+ }
+ if (fragments == null) {
+ return null;
+ }
+
+ ClassToInstanceMap<Fragment> fragmentsMap = MutableClassToInstanceMap.create();
+ for (Fragment fragment : fragments) {
+ fragmentsMap.put(fragment.getClass(), fragment);
+ }
+
+ return new BuildConfigurationValue(
+ new BuildConfiguration(directories, fragmentsMap, key.getBuildOptions(),
+ !key.actionsEnabled()));
+ }
+
+ private Set<Fragment> getConfigurationFragments(BuildConfigurationValue.Key key, Environment env)
+ throws InvalidConfigurationException {
+ // Get SkyKeys for the fragments we need to load.
+ Set<SkyKey> fragmentKeys = new LinkedHashSet<>();
+ for (Class<? extends BuildConfiguration.Fragment> fragmentClass : key.getFragments()) {
+ fragmentKeys.add(ConfigurationFragmentValue.key(key.getBuildOptions(), fragmentClass));
+ }
+
+ // Load them as Skyframe deps.
+ Map<SkyKey, ValueOrException<InvalidConfigurationException>> fragmentDeps =
+ env.getValuesOrThrow(fragmentKeys, InvalidConfigurationException.class);
+ if (env.valuesMissing()) {
+ return null;
+ }
+
+ // Collect and return the results.
+ ImmutableSet.Builder<Fragment> fragments = ImmutableSet.builder();
+ for (ValueOrException<InvalidConfigurationException> value : fragmentDeps.values()) {
+ fragments.add(((ConfigurationFragmentValue) value.get()).getFragment());
+ }
+ return fragments.build();
+ }
+
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return null;
+ }
+
+ private static final class BuildConfigurationFunctionException extends SkyFunctionException {
+ public BuildConfigurationFunctionException(InvalidConfigurationException e) {
+ super(e, Transience.PERSISTENT);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java
new file mode 100644
index 0000000000..10f5d30776
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java
@@ -0,0 +1,113 @@
+// Copyright 2015 Google Inc. 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.common.base.Preconditions;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A Skyframe value representing a {@link BuildConfiguration}.
+ */
+// TODO(bazel-team): mark this immutable when BuildConfiguration is immutable.
+// @Immutable
+@ThreadSafe
+public class BuildConfigurationValue implements SkyValue {
+
+ private final BuildConfiguration configuration;
+
+ BuildConfigurationValue(BuildConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ public BuildConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ /**
+ * Returns the key for a requested configuration.
+ *
+ * @param fragments the fragments the configuration should contain
+ * @param buildOptions the build options the fragments should be built from
+ */
+ @ThreadSafe
+ public static SkyKey key(Set<Class<? extends BuildConfiguration.Fragment>> fragments,
+ BuildOptions buildOptions) {
+ return new SkyKey(SkyFunctions.BUILD_CONFIGURATION,
+ new Key(fragments, buildOptions, true));
+ }
+
+ /**
+ * Returns the key for a requested action-disabled configuration (actions generated by rules
+ * under the configuration are ignored).
+ *
+ * @param fragments the fragments the configuration should contain
+ * @param buildOptions the build options the fragments should be built from
+ */
+ @ThreadSafe
+ public static SkyKey disabledActionsKey(
+ Set<Class<? extends BuildConfiguration.Fragment>> fragments,
+ BuildOptions buildOptions) {
+ return new SkyKey(SkyFunctions.BUILD_CONFIGURATION,
+ new Key(fragments, buildOptions, false));
+ }
+
+ static final class Key implements Serializable {
+ private final Set<Class<? extends BuildConfiguration.Fragment>> fragments;
+ private final BuildOptions buildOptions;
+ private final boolean enableActions;
+
+ Key(Set<Class<? extends BuildConfiguration.Fragment>> fragments,
+ BuildOptions buildOptions, boolean enableActions) {
+ this.fragments = fragments;
+ this.buildOptions = Preconditions.checkNotNull(buildOptions);
+ this.enableActions = enableActions;
+ }
+
+ Set<Class<? extends BuildConfiguration.Fragment>> getFragments() {
+ return fragments;
+ }
+
+ BuildOptions getBuildOptions() {
+ return buildOptions;
+ }
+
+ boolean actionsEnabled() {
+ return enableActions;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Key)) {
+ return false;
+ }
+ Key otherConfig = (Key) o;
+ return Objects.equals(fragments, otherConfig.fragments)
+ && Objects.equals(buildOptions, otherConfig.buildOptions)
+ && otherConfig.actionsEnabled() == enableActions;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fragments, buildOptions, enableActions);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
index ba0ea07e84..633e95a591 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
@@ -54,6 +54,8 @@ public final class SkyFunctions {
SkyFunctionName.computed("TARGET_COMPLETION");
public static final SkyFunctionName TEST_COMPLETION =
SkyFunctionName.computed("TEST_COMPLETION");
+ public static final SkyFunctionName BUILD_CONFIGURATION =
+ SkyFunctionName.computed("BUILD_CONFIGURATION");
public static final SkyFunctionName CONFIGURATION_FRAGMENT =
SkyFunctionName.computed("CONFIGURATION_FRAGMENT");
public static final SkyFunctionName CONFIGURATION_COLLECTION =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index d445175daa..afb7a50898 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -69,6 +69,7 @@ import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.PackageFactory;
import com.google.devtools.build.lib.packages.PackageIdentifier;
import com.google.devtools.build.lib.packages.Preprocessor;
+import com.google.devtools.build.lib.packages.RuleClassProvider;
import com.google.devtools.build.lib.packages.RuleVisibility;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.pkgcache.FilteringPolicy;
@@ -282,6 +283,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
Predicate<PathFragment> allowedMissingInputs) {
ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator,
immutableDirectories, errorOnExternalFiles);
+ RuleClassProvider ruleClassProvider = pkgFactory.getRuleClassProvider();
// We use an immutable map builder for the nice side effect that it throws if a duplicate key
// is inserted.
ImmutableMap.Builder<SkyFunctionName, SkyFunction> map = ImmutableMap.builder();
@@ -296,9 +298,9 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
map.put(SkyFunctions.PACKAGE_LOOKUP, new PackageLookupFunction(deletedPackages));
map.put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction());
map.put(SkyFunctions.AST_FILE_LOOKUP, new ASTFileLookupFunction(
- pkgLocator, packageManager, pkgFactory.getRuleClassProvider()));
+ pkgLocator, packageManager, ruleClassProvider));
map.put(SkyFunctions.SKYLARK_IMPORTS_LOOKUP, new SkylarkImportLookupFunction(
- pkgFactory.getRuleClassProvider(), pkgFactory));
+ ruleClassProvider, pkgFactory));
map.put(SkyFunctions.GLOB, new GlobFunction());
map.put(SkyFunctions.TARGET_PATTERN, new TargetPatternFunction(pkgLocator));
map.put(SkyFunctions.PREPARE_DEPS_OF_PATTERNS, new PrepareDepsOfPatternsFunction());
@@ -307,12 +309,13 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
reporter, pkgFactory, packageManager, showLoadingProgress, packageFunctionCache,
numPackagesLoaded));
map.put(SkyFunctions.TARGET_MARKER, new TargetMarkerFunction());
- map.put(SkyFunctions.TRANSITIVE_TARGET, new TransitiveTargetFunction());
+ map.put(SkyFunctions.TRANSITIVE_TARGET, new TransitiveTargetFunction(ruleClassProvider));
map.put(SkyFunctions.CONFIGURED_TARGET,
new ConfiguredTargetFunction(new BuildViewProvider()));
map.put(SkyFunctions.ASPECT, new AspectFunction(new BuildViewProvider()));
map.put(SkyFunctions.POST_CONFIGURED_TARGET,
new PostConfiguredTargetFunction(new BuildViewProvider()));
+ map.put(SkyFunctions.BUILD_CONFIGURATION, new BuildConfigurationFunction(directories));
map.put(SkyFunctions.CONFIGURATION_COLLECTION, new ConfigurationCollectionFunction(
configurationFactory, configurationPackages));
map.put(SkyFunctions.CONFIGURATION_FRAGMENT, new ConfigurationFragmentFunction(
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;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetValue.java
index 69b9638c6f..e668d5786e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetValue.java
@@ -13,6 +13,7 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
@@ -49,16 +50,19 @@ public class TransitiveTargetValue implements SkyValue {
private NestedSet<Label> transitiveTargets;
@Nullable private NestedSet<Label> transitiveRootCauses;
@Nullable private NoSuchTargetException errorLoadingTarget;
+ private NestedSet<Class<? extends BuildConfiguration.Fragment>> transitiveConfigFragments;
private TransitiveTargetValue(NestedSet<PackageIdentifier> transitiveSuccessfulPkgs,
NestedSet<PackageIdentifier> transitiveUnsuccessfulPkgs, NestedSet<Label> transitiveTargets,
@Nullable NestedSet<Label> transitiveRootCauses,
- @Nullable NoSuchTargetException errorLoadingTarget) {
+ @Nullable NoSuchTargetException errorLoadingTarget,
+ NestedSet<Class<? extends BuildConfiguration.Fragment>> transitiveConfigFragments) {
this.transitiveSuccessfulPkgs = transitiveSuccessfulPkgs;
this.transitiveUnsuccessfulPkgs = transitiveUnsuccessfulPkgs;
this.transitiveTargets = transitiveTargets;
this.transitiveRootCauses = transitiveRootCauses;
this.errorLoadingTarget = errorLoadingTarget;
+ this.transitiveConfigFragments = transitiveConfigFragments;
}
private void writeObject(ObjectOutputStream out) throws IOException {
@@ -75,6 +79,7 @@ public class TransitiveTargetValue implements SkyValue {
// TODO(bazel-team): Deal with this properly once we have efficient serialization of NestedSets.
out.writeObject(transitiveRootCauses);
out.writeObject(errorLoadingTarget);
+ out.writeObject(transitiveConfigFragments);
}
@SuppressWarnings("unchecked")
@@ -90,22 +95,26 @@ public class TransitiveTargetValue implements SkyValue {
transitiveTargets = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
transitiveRootCauses = (NestedSet<Label>) in.readObject();
errorLoadingTarget = (NoSuchTargetException) in.readObject();
+ transitiveConfigFragments =
+ (NestedSet<Class<? extends BuildConfiguration.Fragment>>) in.readObject();
}
static TransitiveTargetValue unsuccessfulTransitiveLoading(
NestedSet<PackageIdentifier> transitiveSuccessfulPkgs,
NestedSet<PackageIdentifier> transitiveUnsuccessfulPkgs, NestedSet<Label> transitiveTargets,
- NestedSet<Label> rootCauses, @Nullable NoSuchTargetException errorLoadingTarget) {
+ NestedSet<Label> rootCauses, @Nullable NoSuchTargetException errorLoadingTarget,
+ NestedSet<Class<? extends BuildConfiguration.Fragment>> transitiveConfigFragments) {
return new TransitiveTargetValue(transitiveSuccessfulPkgs, transitiveUnsuccessfulPkgs,
- transitiveTargets, rootCauses, errorLoadingTarget);
+ transitiveTargets, rootCauses, errorLoadingTarget, transitiveConfigFragments);
}
static TransitiveTargetValue successfulTransitiveLoading(
NestedSet<PackageIdentifier> transitiveSuccessfulPkgs,
NestedSet<PackageIdentifier> transitiveUnsuccessfulPkgs,
- NestedSet<Label> transitiveTargets) {
+ NestedSet<Label> transitiveTargets,
+ NestedSet<Class<? extends BuildConfiguration.Fragment>> transitiveConfigFragments) {
return new TransitiveTargetValue(transitiveSuccessfulPkgs, transitiveUnsuccessfulPkgs,
- transitiveTargets, null, null);
+ transitiveTargets, null, null, transitiveConfigFragments);
}
/** Returns the error, if any, from loading the target. */
@@ -135,6 +144,29 @@ public class TransitiveTargetValue implements SkyValue {
return transitiveRootCauses;
}
+ /**
+ * Returns the set of {@link BuildConfiguration.Fragment} classes required to configure a
+ * rule's transitive closure. These are used to instantiate the right
+ * {@link ConfigurationFragmentValue} instances for a rule's {@link BuildConfigurationValue}.
+ *
+ * <p>This provides the basis for rule-scoped configurations. For example, Java-related build
+ * flags have nothing to do with C++. So changing a Java flag shouldn't invalidate a C++ rule
+ * (unless it has transitive dependencies on other Java rules). Likewise, a C++ rule shouldn't
+ * fail because the Java configuration doesn't recognize the chosen architecture.
+ *
+ * <p>The general principle is that a rule can be influenced by the configuration parameters it
+ * directly uses and the configuration parameters its transitive dependencies use (since it
+ * reads its dependencies as part of analysis). So we need to 1) determine which configuration
+ * fragments provide these parameters, 2) load those fragments, then 3) create a configuration
+ * from them to feed the rule's configured target. This provides the first step.
+ *
+ * <p>See
+ * {@link com.google.devtools.build.lib.packages.RuleClass.Builder#requiredConfigurationFragments}
+ */
+ NestedSet<Class<? extends BuildConfiguration.Fragment>> getTransitiveConfigFragments() {
+ return transitiveConfigFragments;
+ }
+
@ThreadSafe
public static SkyKey key(Label label) {
return new SkyKey(SkyFunctions.TRANSITIVE_TARGET, label);