Plumbs transition key data through to ConfiguredTargetAndData and makes getSplitPrerequisiteConfiguredTargetAndTargets use transition keys instead of reading CPU information from BuildOptions.
RELNOTES: None
PiperOrigin-RevId: 299425217
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java b/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java
index 5ed5883..7dc403c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/Dependency.java
@@ -29,19 +29,20 @@
* <p>The dep's configuration can be specified in one of two ways:
*
* <p>Explicit configurations: includes the target and the configuration of the dependency
- * configured target and any aspects that may be required, as well as the configurations for
- * these aspects.
+ * configured target and any aspects that may be required, as well as the configurations for these
+ * aspects and an optional transition key. {@link Dependency#getTransitionKey} provides some more
+ * context on transition keys.
*
- * <p>Configuration transitions: includes the target and the desired configuration transitions
- * that should be applied to produce the dependency's configuration. It's the caller's
- * responsibility to construct an actual configuration out of that. A set of aspects is also
- * included; the caller must also construct configurations for each of these.
+ * <p>Configuration transitions: includes the target and the desired configuration transitions that
+ * should be applied to produce the dependency's configuration. It's the caller's responsibility to
+ * construct an actual configuration out of that. A set of aspects is also included; the caller must
+ * also construct configurations for each of these.
*
* <p>Note that the presence of an aspect here does not necessarily mean that it will be created.
* They will be filtered based on the {@link TransitiveInfoProvider} instances their associated
- * configured targets have (we cannot do that here because the configured targets are not
- * available yet). No error or warning is reported in this case, because it is expected that rules
- * sometimes over-approximate the providers they supply in their definitions.
+ * configured targets have (we cannot do that here because the configured targets are not available
+ * yet). No error or warning is reported in this case, because it is expected that rules sometimes
+ * over-approximate the providers they supply in their definitions.
*/
public abstract class Dependency {
@@ -62,9 +63,11 @@
*/
public static Dependency withConfiguration(Label label, BuildConfiguration configuration) {
return new ExplicitConfigurationDependency(
- label, configuration,
+ label,
+ configuration,
AspectCollection.EMPTY,
- ImmutableMap.<AspectDescriptor, BuildConfiguration>of());
+ ImmutableMap.<AspectDescriptor, BuildConfiguration>of(),
+ null);
}
/**
@@ -80,8 +83,30 @@
for (AspectDescriptor aspect : aspects.getAllAspects()) {
aspectBuilder.put(aspect, configuration);
}
- return new ExplicitConfigurationDependency(label, configuration, aspects,
- aspectBuilder.build());
+ return new ExplicitConfigurationDependency(
+ label, configuration, aspects, aspectBuilder.build(), null);
+ }
+
+ /**
+ * Creates a new {@link Dependency} with the given configuration, aspects, and transition key. The
+ * configuration is also applied to all aspects. This should be preferred over {@link
+ * Dependency#withConfigurationAndAspects} if the {@code configuration} was derived from a {@link
+ * ConfigurationTransition}, and so there is a corresponding transition key.
+ *
+ * <p>The configuration and aspects must not be {@code null}.
+ */
+ public static Dependency withConfigurationAspectsAndTransitionKey(
+ Label label,
+ BuildConfiguration configuration,
+ AspectCollection aspects,
+ @Nullable String transitionKey) {
+ ImmutableMap.Builder<AspectDescriptor, BuildConfiguration> aspectBuilder =
+ new ImmutableMap.Builder<>();
+ for (AspectDescriptor aspect : aspects.getAllAspects()) {
+ aspectBuilder.put(aspect, configuration);
+ }
+ return new ExplicitConfigurationDependency(
+ label, configuration, aspects, aspectBuilder.build(), transitionKey);
}
/**
@@ -96,7 +121,7 @@
AspectCollection aspects,
Map<AspectDescriptor, BuildConfiguration> aspectConfigurations) {
return new ExplicitConfigurationDependency(
- label, configuration, aspects, ImmutableMap.copyOf(aspectConfigurations));
+ label, configuration, aspects, ImmutableMap.copyOf(aspectConfigurations), null);
}
/**
@@ -159,6 +184,14 @@
public abstract BuildConfiguration getAspectConfiguration(AspectDescriptor aspect);
/**
+ * Returns the key of a configuration transition, if exists, associated with this dependency. See
+ * {@link ConfigurationTransition#apply} for more details.
+ *
+ * @throws IllegalStateException if {@link #hasExplicitConfiguration()} returns false.
+ */
+ public abstract String getTransitionKey();
+
+ /**
* Implementation of a dependency with no configuration, suitable for, e.g., source files or
* visibility.
*/
@@ -194,6 +227,12 @@
return null;
}
+ @Nullable
+ @Override
+ public String getTransitionKey() {
+ return null;
+ }
+
@Override
public int hashCode() {
return label.hashCode();
@@ -221,15 +260,19 @@
private final BuildConfiguration configuration;
private final AspectCollection aspects;
private final ImmutableMap<AspectDescriptor, BuildConfiguration> aspectConfigurations;
+ @Nullable private final String transitionKey;
public ExplicitConfigurationDependency(
- Label label, BuildConfiguration configuration,
+ Label label,
+ BuildConfiguration configuration,
AspectCollection aspects,
- ImmutableMap<AspectDescriptor, BuildConfiguration> aspectConfigurations) {
+ ImmutableMap<AspectDescriptor, BuildConfiguration> aspectConfigurations,
+ @Nullable String transitionKey) {
super(label);
this.configuration = Preconditions.checkNotNull(configuration);
this.aspects = Preconditions.checkNotNull(aspects);
this.aspectConfigurations = Preconditions.checkNotNull(aspectConfigurations);
+ this.transitionKey = transitionKey;
}
@Override
@@ -258,9 +301,15 @@
return aspectConfigurations.get(aspect);
}
+ @Nullable
+ @Override
+ public String getTransitionKey() {
+ return transitionKey;
+ }
+
@Override
public int hashCode() {
- return Objects.hash(label, configuration, aspectConfigurations);
+ return Objects.hash(label, configuration, aspectConfigurations, transitionKey);
}
@Override
@@ -325,6 +374,12 @@
}
@Override
+ public String getTransitionKey() {
+ throw new IllegalStateException(
+ "This dependency has a transition, not an explicit configuration.");
+ }
+
+ @Override
public int hashCode() {
return Objects.hash(label, transition, aspects);
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index b1b13d0..65f99ac 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -49,7 +49,6 @@
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
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.CoreOptions;
import com.google.devtools.build.lib.analysis.config.FragmentCollection;
import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
@@ -856,7 +855,7 @@
}
/**
- * Returns the prerequisites keyed by the CPU of their configurations. If the split transition
+ * Returns the prerequisites keyed by their configuration transition keys. If the split transition
* is not active (e.g. split() returned an empty list), the key is an empty Optional.
*/
public Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>>
@@ -891,8 +890,8 @@
}
/**
- * Returns the prerequisites keyed by the CPU of their configurations. If the split transition is
- * not active (e.g. split() returned an empty list), the key is an empty Optional.
+ * Returns the prerequisites keyed by their transition keys. If the split transition is not active
+ * (e.g. split() returned an empty list), the key is an empty Optional.
*/
public Map<Optional<String>, List<ConfiguredTargetAndData>>
getSplitPrerequisiteConfiguredTargetAndTargets(String attributeName) {
@@ -913,28 +912,23 @@
List<ConfiguredTargetAndData> deps = getConfiguredTargetAndTargetDeps(attributeName);
if (SplitTransition.equals(fromOptions, splitOptions.values())) {
- // The split transition is not active. Defer the decision on which CPU to use.
+ // The split transition is not active.
return ImmutableMap.of(Optional.<String>absent(), deps);
}
- Set<String> cpus = new HashSet<>();
- for (BuildOptions options : splitOptions.values()) {
- // This method should only be called when the split config is enabled on the command line, in
- // which case this cpu can't be null.
- cpus.add(options.get(CoreOptions.class).cpu);
- }
-
// Use an ImmutableListMultimap.Builder here to preserve ordering.
ImmutableListMultimap.Builder<Optional<String>, ConfiguredTargetAndData> result =
ImmutableListMultimap.builder();
for (ConfiguredTargetAndData t : deps) {
- if (t.getConfiguration() != null) {
- result.put(Optional.of(t.getConfiguration().getCpu()), t);
- } else {
- // Source files don't have a configuration, so we add them to all architecture entries.
- for (String cpu : cpus) {
- result.put(Optional.of(cpu), t);
+ if (t.getTransitionKey() == null
+ || t.getTransitionKey().equals(ConfigurationTransition.PATCH_TRANSITION_KEY)) {
+ // The target doesn't have a specific transition key associated. This likely means it's a
+ // non-configurable target, e.g. files, package groups. Pan out to all available keys.
+ for (String key : splitOptions.keySet()) {
+ result.put(Optional.of(key), t);
}
+ } else {
+ result.put(Optional.of(t.getTransitionKey()), t);
}
}
return Multimaps.asMap(result.build());
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
index b8732d9..b1303d9 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
@@ -53,6 +53,7 @@
import com.google.devtools.build.lib.skyframe.TransitiveTargetKey;
import com.google.devtools.build.lib.skyframe.TransitiveTargetValue;
import com.google.devtools.build.lib.util.OrderedSetMultimap;
+import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyKey;
@@ -121,9 +122,10 @@
throws ConfiguredTargetFunction.DependencyEvaluationException, InterruptedException {
// Maps each Skyframe-evaluated BuildConfiguration to the dependencies that need that
- // configuration. For cases where Skyframe isn't needed to get the configuration (e.g. when
- // we just re-used the original rule's configuration), we should skip this outright.
- Multimap<SkyKey, Map.Entry<DependencyKind, Dependency>> keysToEntries =
+ // configuration paired with a transition key corresponding to the BuildConfiguration. For cases
+ // where Skyframe isn't needed to get the configuration (e.g. when we just re-used the original
+ // rule's configuration), we should skip this outright.
+ Multimap<SkyKey, Pair<Map.Entry<DependencyKind, Dependency>, String>> keysToEntries =
LinkedListMultimap.create();
// Stores the result of applying a transition to the current configuration using a
@@ -282,8 +284,8 @@
putOnlyEntry(
resolvedDeps,
dependencyEdge,
- Dependency.withConfigurationAndAspects(
- dep.getLabel(), ctgValue.getConfiguration(), dep.getAspects()));
+ Dependency.withConfigurationAspectsAndTransitionKey(
+ dep.getLabel(), ctgValue.getConfiguration(), dep.getAspects(), null));
continue;
}
@@ -297,15 +299,16 @@
}
try {
- for (BuildOptions options : toOptions.values()) {
+ for (Map.Entry<String, BuildOptions> optionsEntry : toOptions.entrySet()) {
if (sameFragments) {
keysToEntries.put(
BuildConfigurationValue.keyWithPlatformMapping(
platformMappingValue,
defaultBuildOptions,
currentConfiguration.fragmentClasses(),
- BuildOptions.diffForReconstruction(defaultBuildOptions, options)),
- depsEntry);
+ BuildOptions.diffForReconstruction(
+ defaultBuildOptions, optionsEntry.getValue())),
+ new Pair<>(depsEntry, optionsEntry.getKey()));
} else {
keysToEntries.put(
@@ -313,8 +316,9 @@
platformMappingValue,
defaultBuildOptions,
depFragments,
- BuildOptions.diffForReconstruction(defaultBuildOptions, options)),
- depsEntry);
+ BuildOptions.diffForReconstruction(
+ defaultBuildOptions, optionsEntry.getValue())),
+ new Pair<>(depsEntry, optionsEntry.getKey()));
}
}
} catch (OptionsParsingException e) {
@@ -355,8 +359,8 @@
}
BuildConfiguration trimmedConfig =
((BuildConfigurationValue) valueOrException.get()).getConfiguration();
- for (Map.Entry<DependencyKind, Dependency> info : keysToEntries.get(key)) {
- Dependency originalDep = info.getValue();
+ for (Pair<Map.Entry<DependencyKind, Dependency>, String> info : keysToEntries.get(key)) {
+ Dependency originalDep = info.first.getValue();
if (trimmedConfig.trimConfigurationsRetroactively()
&& !originalDep.getAspects().isEmpty()) {
String message =
@@ -368,10 +372,10 @@
throw new ConfiguredTargetFunction.DependencyEvaluationException(
new InvalidConfigurationException(message));
}
- DependencyEdge attr = new DependencyEdge(info.getKey(), originalDep.getLabel());
+ DependencyEdge attr = new DependencyEdge(info.first.getKey(), originalDep.getLabel());
Dependency resolvedDep =
- Dependency.withConfigurationAndAspects(
- originalDep.getLabel(), trimmedConfig, originalDep.getAspects());
+ Dependency.withConfigurationAspectsAndTransitionKey(
+ originalDep.getLabel(), trimmedConfig, originalDep.getAspects(), info.second);
Attribute attribute = attr.dependencyKind.getAttribute();
if (attribute != null && attribute.getTransitionFactory().isSplit()) {
resolvedDeps.put(attr, resolvedDep);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchSplitTransitionProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchSplitTransitionProvider.java
index fc0e372..b566386 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchSplitTransitionProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchSplitTransitionProvider.java
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.rules.objc;
import static com.google.devtools.build.lib.packages.Type.STRING;
+import static com.google.devtools.build.lib.rules.apple.AppleConfiguration.IOS_CPU_PREFIX;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
@@ -303,7 +304,7 @@
}
appleCommandLineOptions.configurationDistinguisher = configurationDistinguisher;
- splitBuildOptions.put(cpu, splitOptions);
+ splitBuildOptions.put(IOS_CPU_PREFIX + cpu, splitOptions);
}
return splitBuildOptions.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 0a81c5f..aa6078d 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -329,7 +329,8 @@
new ConfiguredTargetAndData(
associatedTarget,
targetPkg.getTarget(associatedTarget.getLabel().getName()),
- configuration);
+ configuration,
+ null);
} catch (NoSuchTargetException e) {
throw new IllegalStateException("Name already verified", e);
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java
index d583220..764aa97 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java
@@ -29,10 +29,11 @@
import javax.annotation.Nullable;
/**
- * A container class for a {@link ConfiguredTarget} and associated data, {@link Target} and {@link
- * BuildConfiguration}. In the future, {@link ConfiguredTarget} objects will no longer contain their
- * associated {@link BuildConfiguration}. Consumers that need the {@link Target} or {@link
- * BuildConfiguration} must therefore have access to one of these objects.
+ * A container class for a {@link ConfiguredTarget} and associated data, {@link Target}, {@link
+ * BuildConfiguration}, and an optional transition key. In the future, {@link ConfiguredTarget}
+ * objects will no longer contain their associated {@link BuildConfiguration}. Consumers that need
+ * the {@link Target} or {@link BuildConfiguration} must therefore have access to one of these
+ * objects.
*
* <p>These objects are intended to be short-lived, never stored in Skyframe, since they pair three
* heavyweight objects, a {@link ConfiguredTarget}, a {@link Target} (which holds a {@link
@@ -42,13 +43,18 @@
private final ConfiguredTarget configuredTarget;
private final Target target;
private final BuildConfiguration configuration;
+ @Nullable private final String transitionKey;
@VisibleForTesting
public ConfiguredTargetAndData(
- ConfiguredTarget configuredTarget, Target target, BuildConfiguration configuration) {
+ ConfiguredTarget configuredTarget,
+ Target target,
+ BuildConfiguration configuration,
+ String transitionKey) {
this.configuredTarget = configuredTarget;
this.target = target;
this.configuration = configuration;
+ this.transitionKey = transitionKey;
Preconditions.checkState(
configuredTarget.getLabel().equals(target.getLabel()),
"Unable to construct ConfiguredTargetAndData:"
@@ -104,7 +110,7 @@
}
try {
return new ConfiguredTargetAndData(
- ct, packageValue.getPackage().getTarget(ct.getLabel().getName()), configuration);
+ ct, packageValue.getPackage().getTarget(ct.getLabel().getName()), configuration, null);
} catch (NoSuchTargetException e) {
throw new IllegalStateException("Failed to retrieve target for " + ct, e);
}
@@ -118,7 +124,7 @@
if (configuredTarget.equals(maybeNew)) {
return this;
}
- return new ConfiguredTargetAndData(maybeNew, this.target, configuration);
+ return new ConfiguredTargetAndData(maybeNew, target, configuration, transitionKey);
}
public Target getTarget() {
@@ -132,4 +138,9 @@
public ConfiguredTarget getConfiguredTarget() {
return configuredTarget;
}
+
+ @Nullable
+ public String getTransitionKey() {
+ return transitionKey;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index 04bab2c..446d2a2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -831,7 +831,8 @@
new ConfiguredTargetAndData(
depValue.getConfiguredTarget(),
pkgValue.getPackage().getTarget(depLabel.getName()),
- depConfiguration));
+ depConfiguration,
+ dep.getTransitionKey()));
} catch (NoSuchTargetException e) {
throw new IllegalStateException("Target already verified for " + dep, e);
}
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 234763b..2c165e3 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
@@ -1844,7 +1844,8 @@
new ConfiguredTargetAndData(
mergedTarget,
packageValue.getPackage().getTarget(configuredTarget.getLabel().getName()),
- resolvedConfig));
+ resolvedConfig,
+ null));
} catch (DuplicateException | NoSuchTargetException e) {
throw new IllegalStateException(
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java b/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java
index a2b39f1..8f39f0b 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java
@@ -41,7 +41,7 @@
ConfiguredTarget ct = Iterables.getOnlyElement(result.getTargetsToBuild());
TargetAndConfiguration tac = Iterables.getOnlyElement(result.getTopLevelTargetsWithConfigs());
ConfiguredTargetAndData ctAndData =
- new ConfiguredTargetAndData(ct, tac.getTarget(), tac.getConfiguration());
+ new ConfiguredTargetAndData(ct, tac.getTarget(), tac.getConfiguration(), null);
TopLevelArtifactContext context =
new TopLevelArtifactContext(false, false, OutputGroupInfo.DEFAULT_GROUPS);
ArtifactsToBuild artifactsToBuild =