diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java index 015aff91a8ccd8..73b13105930545 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java @@ -239,9 +239,17 @@ public final OrderedSetMultimap dependentNodeMap( return OrderedSetMultimap.create(); } + // TODO(#10523): Remove this when the migration period for toolchain transitions has ended. + boolean useToolchainTransition = + shouldUseToolchainTransition(node.getConfiguration(), fromRule); OrderedSetMultimap partiallyResolvedDeps = partiallyResolveDependencies( - outgoingLabels, fromRule, attributeMap, toolchainContexts, aspects); + outgoingLabels, + fromRule, + attributeMap, + toolchainContexts, + useToolchainTransition, + aspects); OrderedSetMultimap outgoingEdges = fullyResolveDependencies( @@ -250,6 +258,29 @@ public final OrderedSetMultimap dependentNodeMap( return outgoingEdges; } + /** + * Returns whether or not to use the new toolchain transition. Checks the global incompatible + * change flag and the rule's toolchain transition readiness attribute. + */ + private boolean shouldUseToolchainTransition( + @Nullable BuildConfiguration configuration, @Nullable Rule fromRule) { + // Check whether the global incompatible change flag is set. + if (configuration != null) { + PlatformOptions platformOptions = configuration.getOptions().get(PlatformOptions.class); + if (platformOptions != null && platformOptions.overrideToolchainTransition) { + return true; + } + } + + // Check the rule definition to see if it is ready. + if (fromRule != null && fromRule.getRuleClassObject().useToolchainTransition()) { + return true; + } + + // Default to false. + return false; + } + /** * Factor in the properties of the current rule into the dependency edge calculation. * @@ -264,6 +295,7 @@ public final OrderedSetMultimap dependentNodeMap( @Nullable Rule fromRule, ConfiguredAttributeMapper attributeMap, @Nullable ToolchainCollection toolchainContexts, + boolean useToolchainTransition, Iterable aspects) throws EvalException { OrderedSetMultimap partiallyResolvedDeps = @@ -278,15 +310,29 @@ public final OrderedSetMultimap dependentNodeMap( // use sensible defaults. Not depending on their package makes the error message reporting // a missing toolchain a bit better. // TODO(lberki): This special-casing is weird. Find a better way to depend on toolchains. - partiallyResolvedDeps.put( - TOOLCHAIN_DEPENDENCY, - PartiallyResolvedDependency.builder() - .setLabel(toLabel) - // TODO(#10523): Replace this with a proper transition for the execution platform. - .setTransition(HostTransition.INSTANCE) - // TODO(#10523): Set the toolchainContextKey from ToolchainCollection. - .setPropagatingAspects(ImmutableList.of()) - .build()); + // TODO(#10523): Remove check when this is fully released. + if (useToolchainTransition) { + // We need to create an individual PRD for each distinct toolchain context that contains + // this toolchain, because each has a different ToolchainContextKey. + for (ToolchainContext toolchainContext : + toolchainContexts.getContextsForResolvedToolchain(toLabel)) { + partiallyResolvedDeps.put( + TOOLCHAIN_DEPENDENCY, + PartiallyResolvedDependency.builder() + .setLabel(toLabel) + .setTransition(NoTransition.INSTANCE) + .setToolchainContextKey(toolchainContext.key()) + .build()); + } + } else { + // Legacy approach: use a HostTransition. + partiallyResolvedDeps.put( + TOOLCHAIN_DEPENDENCY, + PartiallyResolvedDependency.builder() + .setLabel(toLabel) + .setTransition(HostTransition.INSTANCE) + .build()); + } continue; } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java index f9e2bad0f5e4ff..2236f5162d98d4 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/PlatformOptions.java @@ -218,6 +218,19 @@ public class PlatformOptions extends FragmentOptions { + " 'test'.") public List>> targetFilterToAdditionalExecConstraints; + @Option( + name = "incompatible_override_toolchain_transition", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = OptionEffectTag.LOADING_AND_ANALYSIS, + metadataTags = { + OptionMetadataTag.INCOMPATIBLE_CHANGE, + OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES + }, + help = + "If set to true, all rules will use the toolchain transition for toolchain dependencies.") + public boolean overrideToolchainTransition; + @Override public PlatformOptions getHost() { PlatformOptions host = (PlatformOptions) getDefault(); @@ -232,6 +245,7 @@ public PlatformOptions getHost() { host.autoConfigureHostPlatform = this.autoConfigureHostPlatform; host.useToolchainResolutionForJavaRules = this.useToolchainResolutionForJavaRules; host.targetPlatformFallback = this.targetPlatformFallback; + host.overrideToolchainTransition = this.overrideToolchainTransition; return host; } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainCollection.java index 41c98f4afac2bb..0ae7a33cc26970 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainCollection.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainCollection.java @@ -18,6 +18,7 @@ import com.google.auto.value.AutoValue; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.cmdline.Label; @@ -72,6 +73,16 @@ public static Builder builder() { return new Builder(); } + /** + * Returns every instance of {@link ToolchainContext} that uses {@code resolvedToolchainLabel} as + * a resolved toolchain. + */ + public ImmutableList getContextsForResolvedToolchain(Label resolvedToolchainLabel) { + return getContextMap().values().stream() + .filter(tc -> tc.resolvedToolchainLabels().contains(resolvedToolchainLabel)) + .collect(ImmutableList.toImmutableList()); + } + /** Builder for ToolchainCollection. */ public static final class Builder { // This is not immutable so that we can check for duplicate keys easily. diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleClassFunctions.java index 8087f537a0e960..adcbeb08564347 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleClassFunctions.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/StarlarkRuleClassFunctions.java @@ -273,6 +273,7 @@ public StarlarkCallable rule( Sequence hostFragments, Boolean starlarkTestable, Sequence toolchains, + boolean useToolchainTransition, String doc, Sequence providesArg, Sequence execCompatibleWith, @@ -353,6 +354,7 @@ public StarlarkCallable rule( bzlModule.label(), bzlModule.bzlTransitiveDigest()); builder.addRequiredToolchains(parseToolchains(toolchains, thread)); + builder.useToolchainTransition(useToolchainTransition); if (execGroups != Starlark.NONE) { Map execGroupDict = diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java index 7a06970a95eb64..134b7b40350db6 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java @@ -715,6 +715,7 @@ public enum ThirdPartyLicenseExistencePolicy { private final Map attributes = new LinkedHashMap<>(); private final Set