Enable rule transition to inspect configurable attributes' value
Fixes https://github.com/bazelbuild/bazel/issues/15157
PiperOrigin-RevId: 558262406
Change-Id: I514c95c0470a2d171a5b276f25b65a4adddf17e9
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
index 4055f14..c18e416 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
@@ -906,7 +906,7 @@
return starlarkVisibleFragments.keySet();
}
- private BuildEventId getEventId() {
+ public BuildEventId getEventId() {
return BuildEventIdUtil.configurationId(checksum());
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java
index 8a6a0a6..b8878b4 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java
@@ -58,11 +58,11 @@
/** The target's label. */
public abstract Label label();
- abstract ImmutableMultimap<String, String> settingsMap();
+ public abstract ImmutableMultimap<String, String> settingsMap();
- abstract ImmutableMap<Label, String> flagSettingsMap();
+ public abstract ImmutableMap<Label, String> flagSettingsMap();
- abstract ImmutableSet<Label> constraintValuesSetting();
+ public abstract ImmutableSet<Label> constraintValuesSetting();
/**
* Whether or not the configuration criteria defined by this target match its actual
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java b/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java
index 630a9d6..1210c8a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java
@@ -106,7 +106,12 @@
.addRuleImplSpecificRequiredConfigFragments(requiredFragments, attributes, configuration);
}
addRequiredFragmentsFromRuleTransitions(
- requiredFragments, target, attributes, configuration.getBuildOptionDetails());
+ configConditions,
+ configuration.checksum(),
+ requiredFragments,
+ target,
+ attributes,
+ configuration.getBuildOptionDetails());
// We consider build settings (which are both targets and configuration) to require themselves.
if (target.isBuildSetting()) {
@@ -216,6 +221,8 @@
* because the child's properties determine that dependency.
*/
private static void addRequiredFragmentsFromRuleTransitions(
+ ConfigConditions configConditions,
+ String configHash,
RequiredConfigFragmentsProvider.Builder requiredFragments,
Rule target,
ConfiguredAttributeMapper attributeMap,
@@ -224,7 +231,7 @@
target
.getRuleClassObject()
.getTransitionFactory()
- .create(RuleTransitionData.create(target))
+ .create(RuleTransitionData.create(target, configConditions.asProviders(), configHash))
.addRequiredFragments(requiredFragments, optionDetails);
}
// We don't set the execution platform in this data because a) that doesn't affect which
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java
index efbd190..8e2daae 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java
@@ -39,6 +39,7 @@
import com.google.devtools.build.lib.packages.BazelStarlarkContext;
import com.google.devtools.build.lib.packages.BazelStarlarkContext.Phase;
import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleTransitionData;
import com.google.devtools.build.lib.packages.StructImpl;
import com.google.devtools.build.lib.packages.SymbolGenerator;
import com.google.devtools.build.lib.starlarkbuildapi.config.ConfigurationTransitionApi;
@@ -95,7 +96,7 @@
// The values in this cache should always be instances of StarlarkTransition, but referencing that
// here results in a circular dependency.
- private final transient Cache<Rule, PatchTransition> ruleTransitionCache =
+ private final transient Cache<RuleTransitionData, PatchTransition> ruleTransitionCache =
Caffeine.newBuilder().weakKeys().build();
private StarlarkDefinedConfigTransition(
@@ -216,7 +217,8 @@
/**
* Returns a cache that can be used to ensure that this {@link StarlarkDefinedConfigTransition}
* results in at most one {@link
- * com.google.devtools.build.lib.analysis.starlark.StarlarkTransition} instance per {@link Rule}.
+ * com.google.devtools.build.lib.analysis.starlark.StarlarkTransition} instance per {@link
+ * RuleTransitionData}.
*
* <p>The cache uses {@link Caffeine#weakKeys} to permit collection of transition objects when the
* corresponding {@link Rule} is collectable. As a consequence, it uses identity comparison for
@@ -231,7 +233,7 @@
* practice to have few or even one transition invoke multiple times over multiple configured
* targets.
*/
- public final Cache<Rule, PatchTransition> getRuleTransitionCache() {
+ public final Cache<RuleTransitionData, PatchTransition> getRuleTransitionCache() {
return ruleTransitionCache;
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
index ce934bf..98cb507 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
@@ -15,6 +15,7 @@
name = "producers",
srcs = glob(["*.java"]),
deps = [
+ "//third_party:guava",
"//src/main/java/com/google/devtools/build/lib/actions:action_lookup_key",
"//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster",
"//src/main/java/com/google/devtools/build/lib/analysis:aspect_collection",
@@ -23,10 +24,13 @@
"//src/main/java/com/google/devtools/build/lib/analysis:config/config_conditions",
"//src/main/java/com/google/devtools/build/lib/analysis:config/config_matching_provider",
"//src/main/java/com/google/devtools/build/lib/analysis:config/configuration_transition_event",
+ "//src/main/java/com/google/devtools/build/lib/analysis:config/core_options",
"//src/main/java/com/google/devtools/build/lib/analysis:config/invalid_configuration_exception",
"//src/main/java/com/google/devtools/build/lib/analysis:config/starlark_transition_cache",
+ "//src/main/java/com/google/devtools/build/lib/analysis:config/toolchain_type_requirement",
"//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/composing_transition",
"//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/configuration_transition",
+ "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/patch_transition",
"//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/transition_collector",
"//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/transition_factory",
"//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
@@ -52,10 +56,12 @@
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
"//src/main/java/com/google/devtools/build/lib/causes",
"//src/main/java/com/google/devtools/build/lib/cmdline",
+ "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
"//src/main/java/com/google/devtools/build/lib/events",
"//src/main/java/com/google/devtools/build/lib/packages",
"//src/main/java/com/google/devtools/build/lib/packages:configured_attribute_mapper",
"//src/main/java/com/google/devtools/build/lib/packages:exec_group",
+ #"//src/main/java/com/google/devtools/build/lib/rules/config",
"//src/main/java/com/google/devtools/build/lib/skyframe:aspect_creation_exception",
"//src/main/java/com/google/devtools/build/lib/skyframe:aspect_key_creator",
"//src/main/java/com/google/devtools/build/lib/skyframe:build_configuration",
@@ -78,7 +84,6 @@
"//src/main/java/net/starlark/java/syntax",
"//src/main/protobuf:failure_details_java_proto",
"//third_party:auto_value",
- "//third_party:guava",
"//third_party:jsr305",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java
index 59f4833..66f556d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java
@@ -16,7 +16,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.InconsistentNullConfigException;
-import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
import com.google.devtools.build.lib.analysis.config.ConfigConditions;
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
@@ -28,6 +27,7 @@
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
@@ -47,7 +47,9 @@
}
// -------------------- Input --------------------
- private final TargetAndConfiguration targetAndConfiguration;
+ private final Label targetLabel;
+ private final Target target;
+ private final BuildConfigurationKey buildConfigurationKey;
@Nullable private final PlatformInfo targetPlatformInfo;
private final TransitiveDependencyState transitiveState;
@@ -66,18 +68,22 @@
private DetailedExitCode mostImportantExitCode;
ConfigConditionsProducer(
- TargetAndConfiguration targetAndConfiguration,
+ Target target,
+ Label targetLabel,
+ BuildConfigurationKey buildConfigurationKey,
@Nullable PlatformInfo targetPlatformInfo,
TransitiveDependencyState transitiveState,
ResultSink sink,
StateMachine runAfter) {
- this.targetAndConfiguration = targetAndConfiguration;
+ this.targetLabel = targetLabel;
+ this.target = target;
+ this.buildConfigurationKey = buildConfigurationKey;
this.targetPlatformInfo = targetPlatformInfo;
this.transitiveState = transitiveState;
this.sink = sink;
this.runAfter = runAfter;
- this.configLabels = computeConfigLabels(targetAndConfiguration.getTarget());
+ this.configLabels = computeConfigLabels(target);
this.prerequisites =
configLabels == null ? null : new ConfiguredTargetAndData[configLabels.size()];
}
@@ -98,7 +104,7 @@
new ConfiguredTargetAndDataProducer(
ConfiguredTargetKey.builder()
.setLabel(configLabels.get(i))
- .setConfiguration(targetAndConfiguration.getConfiguration())
+ .setConfigurationKey(buildConfigurationKey)
.build(),
/* transitionKeys= */ ImmutableList.of(),
transitiveState,
@@ -147,7 +153,6 @@
asConfigConditions.put(
label, ConfigConditions.fromConfiguredTarget(prerequisite, targetPlatformInfo));
} catch (ConfigConditions.InvalidConditionException e) {
- var targetLabel = targetAndConfiguration.getLabel();
String message =
String.format(
"%s is not a valid select() condition for %s.\n",
@@ -155,8 +160,7 @@
+ String.format(
"To inspect the select(), run: bazel query --output=build %s.\n", targetLabel)
+ "For more help, see https://bazel.build/reference/be/functions#select.\n\n";
- sink.acceptConfigConditionsError(
- new ConfiguredValueCreationException(targetAndConfiguration, message));
+ sink.acceptConfigConditionsError(new ConfiguredValueCreationException(target, message));
return runAfter;
}
}
@@ -200,9 +204,7 @@
// The precise error is reported by the dependency that failed to load.
// TODO(gregce): beautify this error: https://github.com/bazelbuild/bazel/issues/11984.
new ConfiguredValueCreationException(
- targetAndConfiguration,
- "errors encountered resolving select() keys for "
- + targetAndConfiguration.getLabel()));
+ target, "errors encountered resolving select() keys for " + targetLabel));
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java
index e68b145..37fbb9e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java
@@ -18,6 +18,7 @@
import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
import com.google.devtools.build.lib.analysis.config.ConfigConditions;
import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
+import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
import com.google.devtools.build.lib.skyframe.toolchains.ToolchainException;
import com.google.devtools.build.lib.skyframe.toolchains.UnloadedToolchainContext;
@@ -56,6 +57,7 @@
// -------------------- Input --------------------
private final UnloadedToolchainContextsInputs unloadedToolchainContextsInputs;
private final TargetAndConfiguration targetAndConfiguration;
+ private final BuildConfigurationKey buildConfigurationKey;
private final TransitiveDependencyState transitiveState;
// -------------------- Output --------------------
@@ -70,9 +72,12 @@
public DependencyContextProducer(
UnloadedToolchainContextsInputs unloadedToolchainContextsInputs,
TargetAndConfiguration targetAndConfiguration,
+ BuildConfigurationKey buildConfigurationKey,
TransitiveDependencyState transitiveState,
ResultSink sink) {
this.unloadedToolchainContextsInputs = unloadedToolchainContextsInputs;
+ this.buildConfigurationKey = buildConfigurationKey;
+ this.unloadedToolchainContexts = null;
this.targetAndConfiguration = targetAndConfiguration;
this.transitiveState = transitiveState;
this.sink = sink;
@@ -104,7 +109,9 @@
}
return new ConfigConditionsProducer(
- targetAndConfiguration,
+ targetAndConfiguration.getTarget(),
+ targetAndConfiguration.getTarget().getLabel(),
+ buildConfigurationKey,
unloadedToolchainContexts == null ? null : unloadedToolchainContexts.getTargetPlatform(),
transitiveState,
(ConfigConditionsProducer.ResultSink) this,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java
index 3f31bd9..581e617 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java
@@ -81,7 +81,9 @@
// If `defaultToolchainContextKey` is null, there's no platform info, incompatibility check
// or toolchain resolution. Short-circuits and computes only the ConfigConditions.
return new ConfigConditionsProducer(
- targetAndConfiguration,
+ targetAndConfiguration.getTarget(),
+ targetAndConfiguration.getTarget().getLabel(),
+ configuredTargetKey.getConfigurationKey(),
/* targetPlatformInfo= */ null,
transitiveState,
(ConfigConditionsProducer.ResultSink) this,
@@ -119,7 +121,9 @@
}
return new ConfigConditionsProducer(
- targetAndConfiguration,
+ targetAndConfiguration.getTarget(),
+ targetAndConfiguration.getTarget().getLabel(),
+ configuredTargetKey.getConfigurationKey(),
targetPlatformInfo,
transitiveState,
(ConfigConditionsProducer.ResultSink) this,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java
index 1e4e06f..b2e65d8 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java
@@ -376,9 +376,10 @@
DependencyError.of(
new DependencyEvaluationException(
new ConfiguredValueCreationException(
+ parameters.target(),
parameters.location(),
message,
- toLabel,
+ parameters.label(),
parameters.eventId(),
/* rootCauses= */ null,
/* detailedExitCode= */ null),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
index ff76717..ff75d1c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
@@ -242,6 +242,7 @@
sink.acceptPrerequisitesAspectError(
new DependencyEvaluationException(
new ConfiguredValueCreationException(
+ parameters.target(),
parameters.location(),
error.getMessage(),
parameters.label(),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java
index c9395c2..fbd2579 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java
@@ -19,35 +19,61 @@
import com.google.auto.value.AutoOneOf;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.ActionLookupKey;
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
+import com.google.devtools.build.lib.analysis.ExecGroupCollection;
import com.google.devtools.build.lib.analysis.InconsistentNullConfigException;
+import com.google.devtools.build.lib.analysis.PlatformConfiguration;
+import com.google.devtools.build.lib.analysis.PlatformOptions;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.ConfigConditions;
import com.google.devtools.build.lib.analysis.config.ConfigurationTransitionEvent;
+import com.google.devtools.build.lib.analysis.config.CoreOptions;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.analysis.config.StarlarkTransitionCache;
+import com.google.devtools.build.lib.analysis.config.ToolchainTypeRequirement;
import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition;
import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
+import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
+import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition.TransitionException;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
+import com.google.devtools.build.lib.causes.AnalysisFailedCause;
+import com.google.devtools.build.lib.causes.Cause;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.NoSuchPackageException;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleTransitionData;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.server.FailureDetails.Analysis;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
+import com.google.devtools.build.lib.skyframe.toolchains.PlatformLookupUtil.InvalidPlatformException;
+import com.google.devtools.build.lib.skyframe.toolchains.ToolchainContextKey;
import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.skyframe.SkyValue;
import com.google.devtools.build.skyframe.state.StateMachine;
import com.google.devtools.common.options.OptionsParsingException;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import net.starlark.java.syntax.Location;
@@ -109,6 +135,7 @@
// -------------------- Input --------------------
private final ConfiguredTargetKey preRuleTransitionKey;
@Nullable private final TransitionFactory<RuleTransitionData> trimmingTransitionFactory;
+ private final PatchTransition toolchainTaggedTrimmingTransition;
private final StarlarkTransitionCache transitionCache;
private final TransitiveDependencyState transitiveState;
@@ -123,12 +150,14 @@
public TargetAndConfigurationProducer(
ConfiguredTargetKey preRuleTransitionKey,
@Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory,
+ PatchTransition toolchainTaggedTrimmingTransition,
StarlarkTransitionCache transitionCache,
TransitiveDependencyState transitiveState,
ResultSink sink,
ExtendedEventHandler eventHandler) {
this.preRuleTransitionKey = preRuleTransitionKey;
this.trimmingTransitionFactory = trimmingTransitionFactory;
+ this.toolchainTaggedTrimmingTransition = toolchainTaggedTrimmingTransition;
this.transitionCache = transitionCache;
this.transitiveState = transitiveState;
this.sink = sink;
@@ -239,15 +268,12 @@
error.getMessage(), TargetUtils.getLocationMaybe(target), error.getDetailedExitCode());
}
- /**
- * Applies the requested rule transition.
- *
- * <p>When the rule transition results in a new configuration, performs an idempotency check and
- * constructs a delegate {@link ConfiguredTargetKey} with the appropriate {@link
- * ConfiguredTargetKey#shouldApplyRuleTransition} value. Otherwise, just looks up the
- * configuration.
- */
- private class RuleTransitionApplier implements StateMachine, TransitionApplier.ResultSink {
+ /** Applies any requested rule transition before producing the final configuration. */
+ private class RuleTransitionApplier
+ implements StateMachine,
+ TransitionApplier.ResultSink,
+ ConfigConditionsProducer.ResultSink,
+ PlatformInfoProducer.ResultSink {
// -------------------- Input --------------------
private final ConfigurationTransition transition;
// -------------------- Internal State --------------------
@@ -257,8 +283,211 @@
this.transition = transition;
}
+ private ConfigConditions configConditions;
+
+ @Nullable private PlatformInfo platformInfo;
+
@Override
- public StateMachine step(Tasks tasks) {
+ public StateMachine step(Tasks tasks) throws InterruptedException {
+
+ UnloadedToolchainContextsInputs unloadedToolchainContextsInputs =
+ getUnloadedToolchainContextsInputs(
+ target, preRuleTransitionKey.getExecutionPlatformLabel());
+
+ if (unloadedToolchainContextsInputs.targetToolchainContextKey() != null) {
+ PlatformConfiguration platformConfiguration =
+ new PlatformConfiguration(preRuleTransitionKey.getConfigurationKey().getOptions());
+ tasks.enqueue(
+ new PlatformInfoProducer(
+ ConfiguredTargetKey.builder()
+ .setLabel(platformConfiguration.getTargetPlatform())
+ .setConfigurationKey(
+ unloadedToolchainContextsInputs
+ .targetToolchainContextKey()
+ .configurationKey())
+ .build(),
+ (PlatformInfoProducer.ResultSink) this,
+ this::computeConfigConditions));
+ } else {
+ this.platformInfo = null;
+ computeConfigConditions(tasks);
+ }
+
+ return DONE;
+ }
+
+ public UnloadedToolchainContextsInputs getUnloadedToolchainContextsInputs(
+ Target target, @Nullable Label parentExecutionPlatformLabel) throws InterruptedException {
+ if (!(target instanceof Rule)) {
+ return UnloadedToolchainContextsInputs.empty();
+ }
+
+ Rule rule = (Rule) target;
+
+ if (!preRuleTransitionKey
+ .getConfigurationKey()
+ .getOptions()
+ .contains(PlatformOptions.class)) {
+ return UnloadedToolchainContextsInputs.empty();
+ }
+ PlatformConfiguration platformConfiguration =
+ new PlatformConfiguration(preRuleTransitionKey.getConfigurationKey().getOptions());
+ var defaultExecConstraintLabels =
+ getExecutionPlatformConstraints(rule, platformConfiguration);
+ var ruleClass = rule.getRuleClassObject();
+ boolean useAutoExecGroups =
+ rule.isAttrDefined("$use_auto_exec_groups", Type.BOOLEAN)
+ ? (boolean) rule.getAttr("$use_auto_exec_groups")
+ : preRuleTransitionKey
+ .getConfigurationKey()
+ .getOptions()
+ .get(CoreOptions.class)
+ .useAutoExecGroups;
+
+ var processedExecGroups =
+ ExecGroupCollection.process(
+ ruleClass.getExecGroups(),
+ defaultExecConstraintLabels,
+ ruleClass.getToolchainTypes(),
+ useAutoExecGroups);
+
+ if (!rule.useToolchainResolution()) {
+ return UnloadedToolchainContextsInputs.create(processedExecGroups, null);
+ }
+
+ return UnloadedToolchainContextsInputs.create(
+ processedExecGroups,
+ createDefaultToolchainContextKey(
+ computeToolchainConfigurationKey(
+ preRuleTransitionKey.getConfigurationKey().getOptions(),
+ toolchainTaggedTrimmingTransition),
+ defaultExecConstraintLabels,
+ /* debugTarget= */ platformConfiguration.debugToolchainResolution(rule.getLabel()),
+ /* useAutoExecGroups= */ useAutoExecGroups,
+ ruleClass.getToolchainTypes(),
+ parentExecutionPlatformLabel));
+ }
+
+ public ToolchainContextKey createDefaultToolchainContextKey(
+ BuildConfigurationKey configurationKey,
+ ImmutableSet<Label> defaultExecConstraintLabels,
+ boolean debugTarget,
+ boolean useAutoExecGroups,
+ ImmutableSet<ToolchainTypeRequirement> toolchainTypes,
+ @Nullable Label parentExecutionPlatformLabel) {
+ ToolchainContextKey.Builder toolchainContextKeyBuilder =
+ ToolchainContextKey.key()
+ .configurationKey(configurationKey)
+ .execConstraintLabels(defaultExecConstraintLabels)
+ .debugTarget(debugTarget);
+
+ // Add toolchain types only if automatic exec groups are not created for this target.
+ if (!useAutoExecGroups) {
+ toolchainContextKeyBuilder.toolchainTypes(toolchainTypes);
+ }
+
+ if (parentExecutionPlatformLabel != null) {
+ // Find out what execution platform the parent used, and force that.
+ // This should only be set for direct toolchain dependencies.
+ toolchainContextKeyBuilder.forceExecutionPlatform(parentExecutionPlatformLabel);
+ }
+ return toolchainContextKeyBuilder.build();
+ }
+
+ private BuildConfigurationKey computeToolchainConfigurationKey(
+ BuildOptions buildOptions, PatchTransition toolchainTaggedTrimmingTransition)
+ throws InterruptedException {
+ // The toolchain context's options are the parent rule's options with manual trimming
+ // auto-applied. This means toolchains don't inherit feature flags. This helps build
+ // performance: if the toolchain context had the exact same configuration of its parent and
+ // that
+ // included feature flags, all the toolchain's dependencies would apply this transition
+ // individually. That creates a lot more potentially expensive applications of that transition
+ // (especially since manual trimming applies to every configured target in the build).
+ //
+ // In other words: without this modification:
+ // parent rule -> toolchain context -> toolchain
+ // -> toolchain dep 1 # applies manual trimming to remove feature flags
+ // -> toolchain dep 2 # applies manual trimming to remove feature flags
+ // ...
+ //
+ // With this modification:
+ // parent rule -> toolchain context # applies manual trimming to remove feature flags
+ // -> toolchain
+ // -> toolchain dep 1
+ // -> toolchain dep 2
+ // ...
+ //
+ // None of this has any effect on rules that don't utilize manual trimming.
+ BuildOptions toolchainOptions =
+ toolchainTaggedTrimmingTransition.patch(
+ new BuildOptionsView(
+ buildOptions, toolchainTaggedTrimmingTransition.requiresOptionFragments()),
+ eventHandler);
+ return BuildConfigurationKey.withoutPlatformMapping(toolchainOptions);
+ }
+
+ private ImmutableSet<Label> getExecutionPlatformConstraints(
+ Rule rule, @Nullable PlatformConfiguration platformConfiguration) {
+ if (platformConfiguration == null) {
+ return ImmutableSet.of(); // See NoConfigTransition.
+ }
+ NonconfigurableAttributeMapper mapper = NonconfigurableAttributeMapper.of(rule);
+ ImmutableSet.Builder<Label> execConstraintLabels = new ImmutableSet.Builder<>();
+
+ execConstraintLabels.addAll(rule.getRuleClassObject().getExecutionPlatformConstraints());
+ if (rule.getRuleClassObject()
+ .hasAttr(RuleClass.EXEC_COMPATIBLE_WITH_ATTR, BuildType.LABEL_LIST)) {
+ execConstraintLabels.addAll(
+ mapper.get(RuleClass.EXEC_COMPATIBLE_WITH_ATTR, BuildType.LABEL_LIST));
+ }
+
+ execConstraintLabels.addAll(
+ platformConfiguration.getAdditionalExecutionConstraintsFor(rule.getLabel()));
+
+ return execConstraintLabels.build();
+ }
+
+ @CanIgnoreReturnValue
+ public StateMachine computeConfigConditions(Tasks tasks) {
+ tasks.enqueue(
+ new ConfigConditionsProducer(
+ target,
+ preRuleTransitionKey.getLabel(),
+ preRuleTransitionKey.getConfigurationKey(),
+ platformInfo,
+ transitiveState,
+ (ConfigConditionsProducer.ResultSink) this,
+ this::computeTransition));
+ return DONE;
+ }
+
+ public StateMachine computeTransition(Tasks tasks) {
+ // logic to compute transition with ConfigConditions
+ var transitionData =
+ RuleTransitionData.create(
+ target.getAssociatedRule(),
+ configConditions != null ? configConditions.asProviders() : null,
+ preRuleTransitionKey.getConfigurationKey().getOptionsChecksum());
+
+ ConfigurationTransition transition = null;
+
+ TransitionFactory<RuleTransitionData> transitionFactory =
+ target.getAssociatedRule().getRuleClassObject().getTransitionFactory();
+ if (transitionFactory != null) {
+ transition = transitionFactory.create(transitionData);
+ }
+
+ boolean isAlias = target.getAssociatedRule().getName().equals("alias");
+
+ if (trimmingTransitionFactory != null && !isAlias) {
+ var trimmingTransition = trimmingTransitionFactory.create(transitionData);
+ if (transition != null) {
+ transition = ComposingTransition.of(transition, trimmingTransition);
+ } else {
+ transition = trimmingTransition;
+ }
+ }
return new TransitionApplier(
preRuleTransitionKey.getConfigurationKey(),
transition,
@@ -289,6 +518,26 @@
emitTransitionErrorMessage(e.getMessage());
}
+ @Override
+ public void acceptConfigConditionsError(ConfiguredValueCreationException e) {
+ emitTransitionErrorMessage(e.getMessage());
+ }
+
+ @Override
+ public void acceptConfigConditions(ConfigConditions configConditions) {
+ this.configConditions = configConditions;
+ }
+
+ @Override
+ public void acceptPlatformInfo(PlatformInfo info) {
+ this.platformInfo = info;
+ }
+
+ @Override
+ public void acceptPlatformInfoError(InvalidPlatformException error) {
+ emitTransitionErrorMessage(error.getMessage());
+ }
+
private StateMachine processTransitionedKey(Tasks tasks) {
if (configurationKey == null) {
return DONE; // There was an error.
@@ -400,22 +649,44 @@
private void emitError(
String message, @Nullable Location location, @Nullable DetailedExitCode exitCode) {
+ Cause cause =
+ new AnalysisFailedCause(
+ preRuleTransitionKey.getLabel(),
+ configurationIdMessage(preRuleTransitionKey.getConfigurationKey().getOptionsChecksum()),
+ exitCode != null ? exitCode : createDetailedExitCode(message));
sink.acceptTargetAndConfigurationError(
TargetAndConfigurationError.of(
new ConfiguredValueCreationException(
+ target,
location,
message,
- preRuleTransitionKey.getLabel(),
+ target.getLabel(),
configurationId(preRuleTransitionKey.getConfigurationKey()),
- /* rootCauses= */ null,
- exitCode)));
+ NestedSetBuilder.create(Order.STABLE_ORDER, cause),
+ exitCode != null ? exitCode : createDetailedExitCode(message))));
+ }
+
+ public static ConfigurationId configurationIdMessage(@Nullable String optionsCheckSum) {
+ if (optionsCheckSum == null) {
+ return ConfigurationId.newBuilder().setId("none").build();
+ }
+ return ConfigurationId.newBuilder().setId(optionsCheckSum).build();
+ }
+
+ public static DetailedExitCode createDetailedExitCode(String message) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setAnalysis(
+ Analysis.newBuilder().setCode(Analysis.Code.CONFIGURED_VALUE_CREATION_FAILED))
+ .build());
}
// Public for Cquery.
@Nullable
public static ConfigurationTransition computeTransition(
Rule rule, @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory) {
- var transitionData = RuleTransitionData.create(rule);
+ var transitionData = RuleTransitionData.create(rule, /* configConditions= */ null, "");
ConfigurationTransition transition = null;
@@ -424,8 +695,8 @@
if (transitionFactory != null) {
transition = transitionFactory.create(transitionData);
}
-
- if (trimmingTransitionFactory != null) {
+ boolean isAlias = rule.getAssociatedRule().getName().equals("alias");
+ if (trimmingTransitionFactory != null && !isAlias) {
var trimmingTransition = trimmingTransitionFactory.create(transitionData);
if (transition != null) {
transition = ComposingTransition.of(transition, trimmingTransition);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java
index a41e513..95f7780 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java
@@ -17,24 +17,32 @@
import static com.google.devtools.build.lib.analysis.starlark.FunctionTransitionUtil.applyAndValidate;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
import com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition;
import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.BuildType.SelectorList;
+import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
import com.google.devtools.build.lib.packages.RawAttributeMapper;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleTransitionData;
import com.google.devtools.build.lib.packages.StructImpl;
import com.google.devtools.build.lib.packages.StructProvider;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* Implements {@link TransitionFactory} to provide a starlark-defined transition that rules can
@@ -73,7 +81,11 @@
// we wouldn't need {@code rule} in the cache key.
return starlarkDefinedConfigTransition
.getRuleTransitionCache()
- .get(ruleData.rule(), this::createTransition);
+ .get(
+ ruleData,
+ x ->
+ createTransition(
+ ruleData.rule(), ruleData.configConditions(), ruleData.configHash()));
}
@Override
@@ -81,15 +93,33 @@
return TransitionType.RULE;
}
- private FunctionPatchTransition createTransition(Rule rule) {
+ private FunctionPatchTransition createTransition(
+ Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions, String configHash) {
LinkedHashMap<String, Object> attributes = new LinkedHashMap<>();
RawAttributeMapper attributeMapper = RawAttributeMapper.of(rule);
+ ConfiguredAttributeMapper configuredAttributeMapper =
+ ConfiguredAttributeMapper.of(rule, configConditions, configHash, false);
+ ImmutableList<String> transitionOutputs = this.starlarkDefinedConfigTransition.getOutputs();
for (Attribute attribute : rule.getAttributes()) {
Object val = attributeMapper.getRawAttributeValue(rule, attribute);
- if (val instanceof BuildType.SelectorList) {
- // For now, don't allow access to attributes that read selects.
- // TODO(b/121134880): make this restriction more fine grained.
- continue;
+ boolean shouldResolveSelect = true;
+ if (val instanceof BuildType.SelectorList && configConditions != null) {
+ for (Object label : ((SelectorList) val).getKeyLabels()) {
+ ConfigMatchingProvider configMatchingProvider = configConditions.get(label);
+ if (checkIfAttributeSelectOnAFlagTransitionChanges(
+ configMatchingProvider, transitionOutputs)) {
+ shouldResolveSelect = false;
+ break;
+ }
+ }
+ if (shouldResolveSelect) {
+ val =
+ configuredAttributeMapper.get(
+ attribute.getName(),
+ configuredAttributeMapper.getAttributeType(attribute.getName()));
+ } else {
+ continue;
+ }
}
attributes.put(
Attribute.getStarlarkName(attribute.getPublicName()), Attribute.valueToStarlark(val));
@@ -97,12 +127,35 @@
StructImpl attrObject =
StructProvider.STRUCT.create(
attributes,
- "No attribute '%s'. Either this attribute does "
- + "not exist for this rule or is set by a select. Starlark rule transitions "
- + "currently cannot read attributes behind selects.");
+ "No attribute '%s'. Either this attribute does not exist for this rule or the attribute"
+ + " was not resolved because it is set by a select that reads flags the transition"
+ + " may set.");
return new FunctionPatchTransition(attrObject);
}
+ private boolean checkIfAttributeSelectOnAFlagTransitionChanges(
+ ConfigMatchingProvider configMatchingProvider, ImmutableList<String> transitionOutputs) {
+ // check settingMap
+ Set<String> nativeFlagLabels = new HashSet<>();
+ for (String key : configMatchingProvider.settingsMap().keySet()) {
+ String modified = "//command_line_option:" + key;
+ nativeFlagLabels.add(modified);
+ }
+ // check flags values
+ ImmutableMap<Label, String> flagSettingsMap = configMatchingProvider.flagSettingsMap();
+ Set<String> flagLabels = new HashSet<>();
+ for (Label flag : flagSettingsMap.keySet()) {
+ flagLabels.add(flag.getCanonicalForm());
+ }
+
+ for (String output : transitionOutputs) {
+ if (nativeFlagLabels.contains(output) || flagLabels.contains(output)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** The actual transition used by the rule. */
private final class FunctionPatchTransition extends StarlarkTransition
implements PatchTransition {
diff --git a/src/main/java/com/google/devtools/build/lib/packages/BUILD b/src/main/java/com/google/devtools/build/lib/packages/BUILD
index da7b1ed..dbe0b48 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/packages/BUILD
@@ -59,6 +59,7 @@
"//src/main/java/com/google/devtools/build/docgen/annot",
"//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
"//src/main/java/com/google/devtools/build/lib/actions:thread_state_receiver",
+ "//src/main/java/com/google/devtools/build/lib/analysis:config/config_matching_provider",
"//src/main/java/com/google/devtools/build/lib/analysis:config/feature_set",
"//src/main/java/com/google/devtools/build/lib/analysis:config/fragment",
"//src/main/java/com/google/devtools/build/lib/analysis:config/fragment_class_set",
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java b/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java
index 81d49ec..8fb037d 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java
@@ -14,7 +14,11 @@
package com.google.devtools.build.lib.packages;
import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
+import com.google.devtools.build.lib.cmdline.Label;
+import javax.annotation.Nullable;
/**
* Helper class which contains data used by a {@link TransitionFactory} to create a transition for
@@ -23,9 +27,15 @@
@AutoValue
public abstract class RuleTransitionData implements TransitionFactory.Data {
- public static RuleTransitionData create(Rule rule) {
- return new AutoValue_RuleTransitionData(rule);
+ public static RuleTransitionData create(
+ Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions, String configHash) {
+ return new AutoValue_RuleTransitionData(rule, configConditions, configHash);
}
public abstract Rule rule();
+
+ @Nullable
+ public abstract ImmutableMap<Label, ConfigMatchingProvider> configConditions();
+
+ public abstract String configHash();
}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
index d6a88b9..c5e965f 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
@@ -138,7 +138,11 @@
if (factory != null) {
output =
factory
- .create(RuleTransitionData.create(target.getAssociatedRule()))
+ .create(
+ RuleTransitionData.create(
+ target.getAssociatedRule(),
+ null,
+ ct.getConfigurationKey().getOptionsChecksum()))
.getName()
.concat(" -> ");
}
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 f1fa6db..07c73b3 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
@@ -407,6 +407,7 @@
new DependencyContextProducer(
unloadedToolchainContextsInputs,
targetAndConfiguration,
+ key.getConfigurationKey(),
state.transitiveState,
(DependencyContextProducer.ResultSink) state));
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index ba9caf5..0d7dd87 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -1160,12 +1160,11 @@
srcs = ["ConfiguredValueCreationException.java"],
deps = [
":sane_analysis_exception",
- "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
- "//src/main/java/com/google/devtools/build/lib/analysis:target_and_configuration",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
"//src/main/java/com/google/devtools/build/lib/causes",
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/collect/nestedset",
+ "//src/main/java/com/google/devtools/build/lib/packages",
"//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
"//src/main/java/net/starlark/java/syntax",
"//src/main/protobuf:failure_details_java_proto",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java
index 7426866..bd71075 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java
@@ -33,6 +33,7 @@
private static ConfiguredValueCreationException withoutMessage(
ConfiguredValueCreationException orig) {
return new ConfiguredValueCreationException(
+ /* target= */ null,
orig.getLocation(),
"",
/* label= */ null,
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 d3139ad..6224ff7 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
@@ -398,12 +398,16 @@
return null;
} catch (ActionConflictException e) {
e.reportTo(env.getListener());
- throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+ throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
} catch (InvalidExecGroupException e) {
- throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+ throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
} catch (AnalysisFailurePropagationException e) {
throw new ConfiguredValueCreationException(
- ctgValue, e.getMessage(), /* rootCauses= */ null, e.getDetailedExitCode());
+ ctgValue.getTarget(),
+ /* buildEventId */ null,
+ e.getMessage(),
+ /* rootCauses= */ null,
+ e.getDetailedExitCode());
}
events.replayOn(env.getListener());
@@ -422,7 +426,11 @@
createDetailedExitCode(event.getMessage())))
.collect(Collectors.toList()));
throw new ConfiguredValueCreationException(
- ctgValue, "Analysis of target '" + target.getLabel() + "' failed", rootCauses, null);
+ ctgValue.getTarget(),
+ null,
+ "Analysis of target '" + target.getLabel() + "' failed",
+ rootCauses,
+ null);
}
Preconditions.checkState(
!analysisEnvironment.hasErrors(), "Analysis environment hasError() but no errors reported");
@@ -462,6 +470,8 @@
configuredTargetKey,
((ConfiguredRuleClassProvider) ruleClassProvider)
.getTrimmingTransitionFactory(),
+ ((ConfiguredRuleClassProvider) ruleClassProvider)
+ .getToolchainTaggedTrimmingTransition(),
buildViewProvider.getSkyframeBuildView().getStarlarkTransitionCache(),
state.computeDependenciesState.transitiveState,
(TargetAndConfigurationProducer.ResultSink) state,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java
index 4677573..837f637 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java
@@ -13,15 +13,16 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
-import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationId;
-import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
import com.google.devtools.build.lib.causes.AnalysisFailedCause;
import com.google.devtools.build.lib.causes.Cause;
import com.google.devtools.build.lib.cmdline.Label;
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;
+import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.server.FailureDetails.Analysis;
import com.google.devtools.build.lib.server.FailureDetails.Analysis.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
@@ -36,6 +37,8 @@
public final class ConfiguredValueCreationException extends Exception
implements SaneAnalysisException {
+ private final Target target;
+ private final Label label;
@Nullable private final Location location;
private final BuildEventId configuration;
private final NestedSet<Cause> rootCauses;
@@ -44,6 +47,7 @@
private final DetailedExitCode detailedExitCode;
public ConfiguredValueCreationException(
+ @Nullable Target target,
@Nullable Location location,
String message,
Label label,
@@ -51,36 +55,52 @@
@Nullable NestedSet<Cause> rootCauses,
@Nullable DetailedExitCode detailedExitCode) {
super(message);
+ this.target = target;
+ this.label = label;
this.location = location;
this.configuration = configuration;
- this.detailedExitCode =
+ DetailedExitCode exitCode =
detailedExitCode != null ? detailedExitCode : createDetailedExitCode(message);
+ this.detailedExitCode = exitCode;
this.rootCauses =
rootCauses != null
? rootCauses
- : NestedSetBuilder.<Cause>stableOrder()
- .add(
- new AnalysisFailedCause(
- label, configuration.getConfiguration(), this.detailedExitCode))
- .build();
+ : NestedSetBuilder.create(
+ Order.STABLE_ORDER, createRootCause(label, configuration, exitCode));
}
public ConfiguredValueCreationException(
- TargetAndConfiguration ctgValue,
+ Target target,
+ @Nullable BuildEventId configuration,
String message,
@Nullable NestedSet<Cause> rootCauses,
@Nullable DetailedExitCode detailedExitCode) {
this(
- ctgValue.getTarget().getLocation(),
+ target,
+ target.getLocation(),
message,
- ctgValue.getLabel(),
- configurationId(ctgValue.getConfiguration()),
+ target.getLabel(),
+ configuration,
rootCauses,
detailedExitCode);
}
- public ConfiguredValueCreationException(TargetAndConfiguration ctgValue, String message) {
- this(ctgValue, message, /*rootCauses=*/ null, /*detailedExitCode=*/ null);
+ public ConfiguredValueCreationException(@Nullable Target target, String message) {
+ this(
+ target,
+ /* configuration= */ null,
+ message,
+ /* rootCauses= */ null,
+ /* detailedExitCode= */ null);
+ }
+
+ @Nullable
+ public Target getTarget() {
+ return target;
+ }
+
+ public Label getLabel() {
+ return label;
}
@Nullable
@@ -109,4 +129,14 @@
.setAnalysis(Analysis.newBuilder().setCode(Code.CONFIGURED_VALUE_CREATION_FAILED))
.build());
}
+
+ private static AnalysisFailedCause createRootCause(
+ Label label, BuildEventId configuration, DetailedExitCode detailedExitCode) {
+ return new AnalysisFailedCause(
+ label,
+ configuration == null
+ ? ConfigurationId.newBuilder().setId("none").build()
+ : configuration.getConfiguration(),
+ detailedExitCode);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java
index 0ff0d47..5c287c2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java
@@ -15,7 +15,9 @@
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationId;
+import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationIdMessage;
import static com.google.devtools.build.lib.analysis.config.transitions.TransitionCollector.NULL_TRANSITION_COLLECTOR;
+import static com.google.devtools.build.lib.analysis.producers.TargetAndConfigurationProducer.createDetailedExitCode;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
@@ -61,11 +63,13 @@
import com.google.devtools.build.lib.analysis.producers.UnloadedToolchainContextsInputs;
import com.google.devtools.build.lib.analysis.starlark.StarlarkAttributeTransitionProvider;
import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition.TransitionException;
+import com.google.devtools.build.lib.causes.AnalysisFailedCause;
import com.google.devtools.build.lib.causes.Cause;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
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;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.events.StoredEventHandler;
@@ -369,7 +373,8 @@
"Cannot compute config conditions"));
throw new ReportedException(
new ConfiguredValueCreationException(
- targetAndConfiguration,
+ targetAndConfiguration.getTarget(),
+ configurationId(targetAndConfiguration.getConfiguration()),
"Cannot compute config conditions",
causes,
getPrioritizedDetailedExitCode(causes)));
@@ -397,7 +402,8 @@
// BuildTool to handle. Calling code needs to be untangled for that to work and pass tests.
throw new UnreportedException(
new ConfiguredValueCreationException(
- targetAndConfiguration,
+ targetAndConfiguration.getTarget(),
+ configurationId(targetAndConfiguration.getConfiguration()),
"Analysis failed",
causes,
getPrioritizedDetailedExitCode(causes)));
@@ -444,14 +450,15 @@
if (splitval.size() < 2) {
throw new UnreportedException(
new ConfiguredValueCreationException(
- targetAndConfiguration, "bad Starlark exec transition reference: " + bzlReference));
+ targetAndConfiguration.getTarget(),
+ "bad Starlark exec transition reference: " + bzlReference));
}
Label bzlFile;
try {
bzlFile = Label.parseCanonical(splitval.get(0));
} catch (LabelSyntaxException e) {
throw new UnreportedException(
- new ConfiguredValueCreationException(targetAndConfiguration, e.getMessage()));
+ new ConfiguredValueCreationException(targetAndConfiguration.getTarget(), e.getMessage()));
}
BzlLoadValue bzlValue = (BzlLoadValue) env.getValue(BzlLoadValue.keyForBuild(bzlFile));
if (bzlValue == null) {
@@ -461,7 +468,7 @@
if (!(transition instanceof StarlarkDefinedConfigTransition)) {
throw new UnreportedException(
new ConfiguredValueCreationException(
- targetAndConfiguration,
+ targetAndConfiguration.getTarget(),
String.valueOf(transition) + " is not a Starlark transition"));
}
return Optional.of(
@@ -572,7 +579,11 @@
cvce != null
? cvce
: new ConfiguredValueCreationException(
- targetAndConfiguration, errorMessage, null, e.getDetailedExitCode()));
+ targetAndConfiguration.getTarget(),
+ configurationId(targetAndConfiguration.getConfiguration()),
+ errorMessage,
+ null,
+ e.getDetailedExitCode()));
} else if (untyped instanceof ConfiguredValueCreationException) {
ConfiguredValueCreationException e = (ConfiguredValueCreationException) untyped;
if (!e.getMessage().isEmpty()) {
@@ -588,7 +599,11 @@
}
throw new ReportedException(
new ConfiguredValueCreationException(
- targetAndConfiguration, e.getMessage(), e.getCauses(), e.getDetailedExitCode()));
+ targetAndConfiguration.getTarget(),
+ configurationId(targetAndConfiguration.getConfiguration()),
+ e.getMessage(),
+ e.getCauses(),
+ e.getDetailedExitCode()));
} else if (untyped instanceof ToolchainException) {
ToolchainException e = (ToolchainException) untyped;
ConfiguredValueCreationException cvce =
@@ -717,12 +732,12 @@
case DEPENDENCY_TRANSITION:
{
TransitionException e = error.dependencyTransition();
- throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+ throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
}
case DEPENDENCY_OPTIONS_PARSING:
{
OptionsParsingException e = error.dependencyOptionsParsing();
- throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+ throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
}
case INVALID_VISIBILITY:
{
@@ -867,14 +882,20 @@
BuildConfigurationValue configuration = targetAndConfiguration.getConfiguration();
Label label = targetAndConfiguration.getLabel();
listener.post(AnalysisRootCauseEvent.withConfigurationValue(configuration, label, message));
+ Cause cause =
+ new AnalysisFailedCause(
+ targetAndConfiguration.getLabel(),
+ configurationIdMessage(targetAndConfiguration.getConfiguration()),
+ createDetailedExitCode(message));
return new DependencyEvaluationException(
new ConfiguredValueCreationException(
+ targetAndConfiguration.getTarget(),
location,
message,
label,
configurationId(configuration),
- /* rootCauses= */ null,
- /* detailedExitCode= */ null),
+ NestedSetBuilder.create(Order.STABLE_ORDER, cause),
+ cause.getDetailedExitCode()),
// These errors occur in dependency resolution, which is attached to the current target.
// i.e. no dependent ConfiguredTargetFunction call happens to report its own error.
/* depReportedOwnError= */ false);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
index c62a9dc..dc1bd67 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
@@ -254,12 +254,17 @@
name = "toolchain_exception",
srcs = ["ToolchainException.java"],
deps = [
+ "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
"//src/main/java/com/google/devtools/build/lib/analysis:target_and_configuration",
+ "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
+ "//src/main/java/com/google/devtools/build/lib/causes",
+ "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
"//src/main/java/com/google/devtools/build/lib/skyframe:configured_value_creation_exception",
"//src/main/java/com/google/devtools/build/lib/skyframe:detailed_exceptions",
"//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
"//src/main/protobuf:failure_details_java_proto",
"//third_party:guava",
+ "//third_party:jsr305",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java
index f121231..ccae8a6 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java
@@ -15,12 +15,20 @@
import com.google.common.base.Strings;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
+import com.google.devtools.build.lib.causes.AnalysisFailedCause;
+import com.google.devtools.build.lib.causes.Cause;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.server.FailureDetails;
+import com.google.devtools.build.lib.server.FailureDetails.Analysis;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.Toolchain.Code;
import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
import com.google.devtools.build.lib.skyframe.DetailedException;
import com.google.devtools.build.lib.util.DetailedExitCode;
+import javax.annotation.Nullable;
/** Base class for exceptions that happen during toolchain resolution. */
public abstract class ToolchainException extends Exception implements DetailedException {
@@ -67,12 +75,38 @@
return (ConfiguredValueCreationException) cause;
}
}
+ Cause cause =
+ new AnalysisFailedCause(
+ targetAndConfiguration.getLabel(),
+ configurationIdMessage(targetAndConfiguration.getConfiguration()),
+ createDetailedExitCode(
+ String.format(
+ "While resolving toolchains for target %s: %s",
+ targetAndConfiguration.getLabel(), getMessage())));
return new ConfiguredValueCreationException(
- targetAndConfiguration,
+ targetAndConfiguration.getTarget(),
+ targetAndConfiguration.getConfiguration().getEventId(),
String.format(
"While resolving toolchains for target %s: %s",
targetAndConfiguration.getLabel(), getMessage()),
- null,
+ NestedSetBuilder.create(Order.STABLE_ORDER, cause),
getDetailedExitCode());
}
+
+ public static ConfigurationId configurationIdMessage(
+ @Nullable BuildConfigurationValue configuration) {
+ if (configuration == null) {
+ return ConfigurationId.newBuilder().setId("none").build();
+ }
+ return ConfigurationId.newBuilder().setId(configuration.checksum()).build();
+ }
+
+ private static DetailedExitCode createDetailedExitCode(String message) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setAnalysis(
+ Analysis.newBuilder().setCode(Analysis.Code.CONFIGURED_VALUE_CREATION_FAILED))
+ .build());
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java b/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
index 3267329..ba0bc22 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
@@ -292,7 +292,6 @@
assertContainsEvent(
"Rule transition only allowed to return a single transitioned configuration.");
}
-
@Test
public void testCanDoBadStuffWithParameterizedTransitionsAndSelects() throws Exception {
writeAllowlistFile();
@@ -339,8 +338,9 @@
getConfiguredTarget("//test");
assertContainsEvent(
"No attribute 'my_configurable_attr'. "
- + "Either this attribute does not exist for this rule or is set by a select. "
- + "Starlark rule transitions currently cannot read attributes behind selects.");
+ + "Either this attribute does not exist for this rule or the attribute "
+ + "was not resolved because it is set by a select that reads flags the transition "
+ + "may set.");
}
@Test
@@ -1557,7 +1557,7 @@
testTarget
.getRuleClassObject()
.getTransitionFactory()
- .create(RuleTransitionData.create(testTarget));
+ .create(RuleTransitionData.create(testTarget, null, ""));
RequiredConfigFragmentsProvider.Builder requiredFragments =
RequiredConfigFragmentsProvider.builder();
ruleTransition.addRequiredFragments(
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
index ceb4711..2634388 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
@@ -62,7 +62,7 @@
Rule rule = scratchRule("a", "empty", "feature_flag_setter(name = 'empty', flag_values = {})");
PatchTransition transition =
new ConfigFeatureFlagTransitionFactory("flag_values")
- .create(RuleTransitionData.create(rule));
+ .create(RuleTransitionData.create(rule, null, ""));
BuildOptions original = getOptionsWithoutFlagFragment();
BuildOptions converted =
@@ -88,7 +88,7 @@
" default_value = 'a')");
PatchTransition transition =
new ConfigFeatureFlagTransitionFactory("flag_values")
- .create(RuleTransitionData.create(rule));
+ .create(RuleTransitionData.create(rule, null, ""));
BuildOptions original = getOptionsWithoutFlagFragment();
BuildOptions converted =
@@ -104,7 +104,7 @@
Rule rule = scratchRule("a", "empty", "feature_flag_setter(name = 'empty', flag_values = {})");
PatchTransition transition =
new ConfigFeatureFlagTransitionFactory("flag_values")
- .create(RuleTransitionData.create(rule));
+ .create(RuleTransitionData.create(rule, null, ""));
Map<Label, String> originalFlagMap = ImmutableMap.of(Label.parseCanonical("//a:flag"), "value");
BuildOptions original = getOptionsWithFlagFragment(originalFlagMap);
@@ -133,7 +133,7 @@
" default_value = 'a')");
PatchTransition transition =
new ConfigFeatureFlagTransitionFactory("flag_values")
- .create(RuleTransitionData.create(rule));
+ .create(RuleTransitionData.create(rule, null, ""));
Map<Label, String> originalFlagMap = ImmutableMap.of(Label.parseCanonical("//a:old"), "value");
Map<Label, String> expectedFlagMap = ImmutableMap.of(Label.parseCanonical("//a:flag"), "a");
@@ -201,34 +201,34 @@
new EqualsTester()
.addEqualityGroup(
// transition for non flags target
- factory.create(RuleTransitionData.create(nonflag)), NoTransition.INSTANCE)
+ factory.create(RuleTransitionData.create(nonflag, null, "")), NoTransition.INSTANCE)
.addEqualityGroup(
// transition with empty map
- factory.create(RuleTransitionData.create(empty)),
+ factory.create(RuleTransitionData.create(empty, null, "")),
// transition produced by same factory on same rule
- factory.create(RuleTransitionData.create(empty)),
+ factory.create(RuleTransitionData.create(empty, null, "")),
// transition produced by similar factory on same rule
- factory2.create(RuleTransitionData.create(empty)),
+ factory2.create(RuleTransitionData.create(empty, null, "")),
// transition produced by same factory on similar rule
- factory.create(RuleTransitionData.create(empty2)),
+ factory.create(RuleTransitionData.create(empty2, null, "")),
// transition produced by similar factory on similar rule
- factory2.create(RuleTransitionData.create(empty2)))
+ factory2.create(RuleTransitionData.create(empty2, null, "")))
.addEqualityGroup(
// transition with flag -> a
- factory.create(RuleTransitionData.create(flagSetterA)),
+ factory.create(RuleTransitionData.create(flagSetterA, null, "")),
// same map, different rule
- factory.create(RuleTransitionData.create(flagSetterA2)),
+ factory.create(RuleTransitionData.create(flagSetterA2, null, "")),
// same map, different factory
- factory2.create(RuleTransitionData.create(flagSetterA)))
+ factory2.create(RuleTransitionData.create(flagSetterA, null, "")))
.addEqualityGroup(
// transition with flag set to different value
- factory.create(RuleTransitionData.create(flagSetterB)))
+ factory.create(RuleTransitionData.create(flagSetterB, null, "")))
.addEqualityGroup(
// transition with different flag set to same value
- factory.create(RuleTransitionData.create(flag2Setter)))
+ factory.create(RuleTransitionData.create(flag2Setter, null, "")))
.addEqualityGroup(
// transition with more flags set
- factory.create(RuleTransitionData.create(bothSetter)))
+ factory.create(RuleTransitionData.create(bothSetter, null, "")))
.testEquals();
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
index 4173c5c..5531aa0 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
@@ -839,7 +839,7 @@
getConfiguration(getConfiguredTarget("//test:toplevel_target")).getOptions();
PatchTransition transition =
new ConfigFeatureFlagTaggedTrimmingTransitionFactory(BaseRuleClasses.TAGGED_TRIMMING_ATTR)
- .create(RuleTransitionData.create((Rule) getTarget("//test:dep")));
+ .create(RuleTransitionData.create((Rule) getTarget("//test:dep"), null, ""));
BuildOptions depOptions =
transition.patch(
new BuildOptionsView(topLevelOptions, transition.requiresOptionFragments()),
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java
index 7ea54c7..aa69a10 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java
@@ -49,10 +49,11 @@
ConfiguredTargetKey.builder()
.setLabel(Label.parseCanonicalUnchecked("//analysis_err"))
.build();
+ TargetAndConfiguration mockTargetAndConfiguration =
+ new TargetAndConfiguration(mock(Target.class), /* configuration= */ null);
ConfiguredValueCreationException analysisException =
new ConfiguredValueCreationException(
- new TargetAndConfiguration(mock(Target.class), /* configuration= */ null),
- "analysis exception");
+ mockTargetAndConfiguration.getTarget(), "analysis exception");
ErrorInfo analysisErrorInfo =
ErrorInfo.fromException(
new ReifiedSkyFunctionException(
diff --git a/src/test/shell/integration/rule_transition_test.sh b/src/test/shell/integration/rule_transition_test.sh
new file mode 100755
index 0000000..6025381
--- /dev/null
+++ b/src/test/shell/integration/rule_transition_test.sh
@@ -0,0 +1,278 @@
+#!/bin/bash
+#
+# Copyright 2023 The Bazel Authors. 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.
+#
+# Test rule transition can inspect configurable attribute.
+
+# --- begin runfiles.bash initialization ---
+# Copy-pasted from Bazel's Bash runfiles library (tools/bash/runfiles/runfiles.bash).
+if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
+ if [[ -f "$0.runfiles_manifest" ]]; then
+ export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+ elif [[ -f "$0.runfiles/MANIFEST" ]]; then
+ export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
+ elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
+ export RUNFILES_DIR="$0.runfiles"
+ fi
+fi
+if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
+ source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
+elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
+ source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \
+ "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
+else
+ echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
+ exit 1
+fi
+# --- end runfiles.bash initialization ---
+
+source "$(rlocation "io_bazel/src/test/shell/integration_test_setup.sh")" \
+ || { echo "integration_test_setup.sh not found!" >&2; exit 1; }
+
+function set_up() {
+ create_new_workspace
+}
+
+function create_transitions() {
+ local pkg="${1}"
+ mkdir -p "${pkg}"
+ cat > "${pkg}/def.bzl" <<EOF
+
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "BuildSettingInfo")
+
+example_package = "${pkg}"
+
+def _transition_impl(settings, attr):
+ if getattr(attr, "apply_transition") and settings["//%s:transition_input_flag" % example_package]:
+ return {"//%s:transition_output_flag" % example_package: True}
+ return {"//%s:transition_output_flag" % example_package: False}
+
+example_transition = transition(
+ implementation = _transition_impl,
+ inputs = ["//%s:transition_input_flag" % example_package],
+ outputs = ["//%s:transition_output_flag" % example_package],
+)
+
+def _rule_impl(ctx):
+ print("Flag value for %s: %s" % (
+ ctx.label.name,
+ ctx.attr._transition_output_flag[BuildSettingInfo].value,
+ ))
+
+transition_attached = rule(
+ implementation = _rule_impl,
+ cfg = example_transition,
+ attrs = {
+ "apply_transition": attr.bool(default = False),
+ "deps": attr.label_list(),
+ "_transition_output_flag": attr.label(default = "//%s:transition_output_flag" % example_package),
+ "_allowlist_function_transition": attr.label(
+ default = "//tools/allowlists/function_transition_allowlist:function_transition_allowlist",
+ ),
+ },
+)
+
+transition_not_attached = rule(
+ implementation = _rule_impl,
+ attrs = {
+ "deps": attr.label_list(),
+ "_transition_output_flag": attr.label(default = "//%s:transition_output_flag" % example_package),
+ },
+)
+EOF
+}
+
+function create_rules_with_incoming_transition_and_selects() {
+ local pkg="${1}"
+ mkdir -p "${pkg}"
+ cat > "${pkg}/BUILD" <<EOF
+load(
+ "//${pkg}:def.bzl",
+ "transition_attached",
+ "transition_not_attached",
+)
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "bool_flag")
+
+bool_flag(
+ name = "transition_input_flag",
+ build_setting_default = True,
+)
+
+bool_flag(
+ name = "transition_output_flag",
+ build_setting_default = False,
+)
+
+config_setting(
+ name = "select_setting",
+ flag_values = {":transition_input_flag": "True"},
+)
+
+# All should print "False" if
+# "--no//${pkg}:transition_input_flag" is
+# specified on the command line
+
+# bazel build :top_level will print the results for all of the targets below
+
+transition_attached(
+ name = "top_level",
+ apply_transition = select({
+ ":select_setting": True,
+ "//conditions:default": False,
+ }),
+ deps = [
+ ":transition_attached_dep",
+ ":transition_not_attached_dep",
+ ],
+)
+
+# Should print "False"
+transition_attached(
+ apply_transition = False,
+ name = "transition_attached_dep",
+ deps = [
+ ":transition_not_attached_dep_of_dep",
+ ],
+)
+
+# Should print "True" when building top_level, "False" otherwise
+transition_not_attached(
+ name = "transition_not_attached_dep",
+)
+
+# Should print "False"
+transition_not_attached(
+ name = "transition_not_attached_dep_of_dep",
+)
+EOF
+}
+
+function test_rule_transition_can_inspect_configure_attributes(){
+ local -r pkg="${FUNCNAME[0]}"
+ create_transitions "${pkg}"
+ create_rules_with_incoming_transition_and_selects "${pkg}"
+
+ bazel build "//${pkg}:top_level" &> $TEST_log || fail "Build failed"
+
+ expect_log 'Flag value for transition_not_attached_dep: True'
+ expect_log 'Flag value for transition_not_attached_dep_of_dep: False'
+ expect_log 'Flag value for transition_attached_dep: False'
+ expect_log 'Flag value for top_level: True'
+}
+
+function test_rule_transition_can_inspect_configure_attributes_with_flag(){
+ local -r pkg="${FUNCNAME[0]}"
+
+ create_transitions "${pkg}"
+ create_rules_with_incoming_transition_and_selects "${pkg}"
+
+ bazel build --no//${pkg}:transition_input_flag "//${pkg}:top_level" &> $TEST_log || fail "Build failed"
+
+ expect_log 'Flag value for transition_not_attached_dep: False'
+ expect_log 'Flag value for transition_not_attached_dep_of_dep: False'
+ expect_log 'Flag value for transition_attached_dep: False'
+ expect_log 'Flag value for top_level: False'
+}
+
+function test_rule_transition_can_not_inspect_configure_attribute() {
+ local -r pkg="${FUNCNAME[0]}"
+
+ # create transition definition
+ mkdir -p "${pkg}"
+ cat > "${pkg}/def.bzl" <<EOF
+
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "BuildSettingInfo")
+
+example_package = "${pkg}"
+
+def _transition_impl(settings, attr):
+ if getattr(attr, "apply_transition") and settings["//%s:transition_input_flag" % example_package]:
+ return {"//%s:transition_output_flag" % example_package: True}
+ return {
+ "//%s:transition_output_flag" % example_package: False,
+ "//%s:transition_input_flag" % example_package: False
+ }
+
+example_transition = transition(
+ implementation = _transition_impl,
+ inputs = ["//%s:transition_input_flag" % example_package],
+ outputs = [
+ "//%s:transition_output_flag" % example_package,
+ "//%s:transition_input_flag" % example_package,
+ ],
+)
+
+def _rule_impl(ctx):
+ print("Flag value for %s: %s" % (
+ ctx.label.name,
+ ctx.attr._transition_output_flag[BuildSettingInfo].value,
+ ))
+
+transition_attached = rule(
+ implementation = _rule_impl,
+ cfg = example_transition,
+ attrs = {
+ "apply_transition": attr.bool(default = False),
+ "deps": attr.label_list(),
+ "_transition_output_flag": attr.label(default = "//%s:transition_output_flag" % example_package),
+ "_allowlist_function_transition": attr.label(
+ default = "//tools/allowlists/function_transition_allowlist:function_transition_allowlist",
+ ),
+ },
+)
+EOF
+
+ # create rules with transition attached
+ cat > "${pkg}/BUILD" <<EOF
+load(
+ "//${pkg}:def.bzl",
+ "transition_attached",
+)
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "bool_flag")
+
+bool_flag(
+ name = "transition_input_flag",
+ build_setting_default = True,
+)
+
+bool_flag(
+ name = "transition_output_flag",
+ build_setting_default = False,
+)
+
+config_setting(
+ name = "select_setting",
+ flag_values = {":transition_input_flag": "True"},
+)
+
+# All should print "False" if
+# "--no//${pkg}:transition_input_flag" is
+# specified on the command line
+
+# bazel build :top_level will print the results for all of the targets below
+
+transition_attached(
+ name = "top_level",
+ apply_transition = select({
+ ":select_setting": True,
+ "//conditions:default": False,
+ }),
+)
+EOF
+ bazel build "//${pkg}:top_level" &> $TEST_log && fail "Build did NOT complete successfully"
+ expect_log "No attribute 'apply_transition'. Either this attribute does not exist for this rule or the attribute was not resolved because it is set by a select that reads flags the transition may set."
+}
+
+run_suite "rule transition tests"
diff --git a/src/test/shell/integration/toolchain_test.sh b/src/test/shell/integration/toolchain_test.sh
index 894d950..1a65538 100755
--- a/src/test/shell/integration/toolchain_test.sh
+++ b/src/test/shell/integration/toolchain_test.sh
@@ -1128,12 +1128,12 @@
bazel build \
--platforms="//${pkg}/platform:not_a_platform" \
"//${pkg}/demo:use" &> $TEST_log && fail "Build failure expected"
- expect_log "While resolving toolchains for target //${pkg}/demo:use: Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
+ expect_log "Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
bazel build \
--host_platform="//${pkg}/platform:not_a_platform" \
"//${pkg}/demo:use" &> $TEST_log && fail "Build failure expected"
- expect_log "While resolving toolchains for target //${pkg}/demo:use: Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
+ expect_log "Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
}
@@ -1884,10 +1884,11 @@
)
EOF
+ echo "START DEBUGGING"
bazel build \
--platforms="//${pkg}:hello" \
"//${pkg}:target" &> $TEST_log && fail "Build succeeded unexpectedly"
- expect_log "While resolving toolchains for target //${pkg}:target: Target //${pkg}:hello was referenced as a platform, but does not provide PlatformInfo"
+ expect_log "Target //${pkg}:hello was referenced as a platform, but does not provide PlatformInfo"
}