Add Starlark API to access result of propagating aspects to targets toolchains for an aspect applied to a target, it can see its providers on the target's toolchains through `ctx.rule.toolchains[TOOLCHAIN_TYPE]` and `ctx.rule.exec_groups[GP_NAME][TOOLCHAIN_TYPE]`. The returned value is a list of providers that the aspect (and its base aspects if any) returned. PiperOrigin-RevId: 654128385 Change-Id: I4f60fbf0b7322259474206b94cf168ccdb1be03d
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AspectBaseTargetResolvedToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/AspectBaseTargetResolvedToolchainContext.java new file mode 100644 index 0000000..e27fd48 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectBaseTargetResolvedToolchainContext.java
@@ -0,0 +1,158 @@ +// Copyright 2024 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. + +package com.google.devtools.build.lib.analysis; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Iterables; +import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget; +import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.packages.Provider; +import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData; +import com.google.devtools.build.lib.skyframe.toolchains.UnloadedToolchainContext; +import javax.annotation.Nullable; +import net.starlark.java.eval.EvalException; +import net.starlark.java.eval.Printer; +import net.starlark.java.eval.Starlark; +import net.starlark.java.eval.StarlarkIndexable; +import net.starlark.java.eval.StarlarkSemantics; + +/** + * A toolchain context for the aspect's base target toolchains. It is used to represent the result + * of applying the aspects propagation to the base target toolchains. + */ +@AutoValue +public abstract class AspectBaseTargetResolvedToolchainContext + implements ResolvedToolchainsDataInterface< + AspectBaseTargetResolvedToolchainContext.ToolchainAspectsProviders> { + + public abstract ImmutableMap<ToolchainTypeInfo, ToolchainAspectsProviders> getToolchains(); + + public static AspectBaseTargetResolvedToolchainContext load( + UnloadedToolchainContext unloadedToolchainContext, + String targetDescription, + ImmutableMultimap<ToolchainTypeInfo, ConfiguredTargetAndData> toolchainTargets) + throws DuplicateException { + + ImmutableMap.Builder<ToolchainTypeInfo, ToolchainAspectsProviders> toolchainsBuilder = + new ImmutableMap.Builder<>(); + + for (var toolchainType : unloadedToolchainContext.toolchainTypeToResolved().keySet()) { + Preconditions.checkArgument(toolchainTargets.get(toolchainType).size() == 1); + + var toolchainTarget = + Iterables.getOnlyElement(toolchainTargets.get(toolchainType)).getConfiguredTarget(); + + if (toolchainTarget instanceof MergedConfiguredTarget mergedConfiguredTarget) { + // Only add the aspects providers from the toolchains that the aspects applied to. + toolchainsBuilder.put( + toolchainType, + new ToolchainAspectsProviders( + mergedConfiguredTarget.getAspectsProviders(), mergedConfiguredTarget.getLabel())); + } else { + // Add empty providers for the toolchains that the aspects did not apply to. + toolchainsBuilder.put( + toolchainType, + new ToolchainAspectsProviders( + new TransitiveInfoProviderMapBuilder().build(), toolchainTarget.getLabel())); + } + } + ImmutableMap<ToolchainTypeInfo, ToolchainAspectsProviders> toolchains = + toolchainsBuilder.buildOrThrow(); + + return new AutoValue_AspectBaseTargetResolvedToolchainContext( + // ToolchainContext: + unloadedToolchainContext.key(), + unloadedToolchainContext.executionPlatform(), + unloadedToolchainContext.targetPlatform(), + unloadedToolchainContext.toolchainTypes(), + unloadedToolchainContext.resolvedToolchainLabels(), + // ResolvedToolchainsDataInterface: + targetDescription, + unloadedToolchainContext.requestedLabelToToolchainType(), + // this: + toolchains); + } + + @Override + @Nullable + public ToolchainAspectsProviders forToolchainType(Label toolchainTypeLabel) { + if (requestedToolchainTypeLabels().containsKey(toolchainTypeLabel)) { + return getToolchains().get(requestedToolchainTypeLabels().get(toolchainTypeLabel)); + } + + return null; + } + + /** + * A Starlark-indexable wrapper used to represent the providers of the aspects applied on the base + * target toolchains. + */ + public static class ToolchainAspectsProviders + implements StarlarkIndexable, ResolvedToolchainData { + + private final TransitiveInfoProviderMap aspectsProviders; + private final Label label; + + private ToolchainAspectsProviders(TransitiveInfoProviderMap aspectsProviders, Label label) { + this.aspectsProviders = aspectsProviders; + this.label = label; + } + + @Override + public final Object getIndex(StarlarkSemantics semantics, Object key) throws EvalException { + Provider constructor = selectExportedProvider(key, "index"); + Object declaredProvider = aspectsProviders.get(constructor.getKey()); + if (declaredProvider != null) { + return declaredProvider; + } + throw Starlark.errorf( + "%s doesn't contain declared provider '%s'", + Starlark.repr(this), constructor.getPrintableName()); + } + + @Override + public boolean containsKey(StarlarkSemantics semantics, Object key) throws EvalException { + return aspectsProviders.get(selectExportedProvider(key, "query").getKey()) != null; + } + + /** + * Selects the provider identified by {@code key}, throwing a Starlark error if the key is not a + * provider or not exported. + */ + private Provider selectExportedProvider(Object key, String operation) throws EvalException { + if (!(key instanceof Provider constructor)) { + throw Starlark.errorf( + "This type only supports %sing by object constructors, got %s instead", + operation, Starlark.type(key)); + } + if (!constructor.isExported()) { + throw Starlark.errorf( + "%s only supports %sing by exported providers. Assign the provider a name " + + "in a top-level assignment statement.", + Starlark.repr(this), operation); + } + return constructor; + } + + @Override + public void repr(Printer printer) { + printer.append("<ToolchainAspectsProviders for toolchain target: " + label + ">"); + } + } +}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AspectContext.java b/src/main/java/com/google/devtools/build/lib/analysis/AspectContext.java index e7ae9f8..08a69c9 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/AspectContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectContext.java
@@ -15,12 +15,15 @@ package com.google.devtools.build.lib.analysis; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableSet.toImmutableSet; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Streams; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap; import com.google.devtools.build.lib.packages.Aspect; import com.google.devtools.build.lib.packages.AspectDescriptor; @@ -30,6 +33,7 @@ import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; +import javax.annotation.Nullable; /** Extends {@link RuleContext} to provide all data available during the analysis of an aspect. */ public final class AspectContext extends RuleContext { @@ -45,18 +49,87 @@ private final PrerequisitesCollection mainAspectPrerequisites; + /** + * The toolchain contexts for the base target. + * + * <p>It only contains the providers created by the aspects that propagate to the toolchains. + */ + @Nullable + private final ToolchainCollection<AspectBaseTargetResolvedToolchainContext> + baseTargetToolchainContexts; + + /** Whether the target uses auto exec groups. */ + private final boolean targetUsesAutoExecGroups; + AspectContext( RuleContext.Builder builder, AspectAwareAttributeMapper aspectAwareAttributeMapper, PrerequisitesCollection ruleAndBaseAspectsPrerequisites, PrerequisitesCollection mainAspectPrerequisites, - ExecGroupCollection execGroupCollection) { + ExecGroupCollection execGroupCollection, + @Nullable + ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts, + boolean targetUsesAutoExecGroups) { super( builder, aspectAwareAttributeMapper, ruleAndBaseAspectsPrerequisites, execGroupCollection); this.aspects = builder.getAspects(); this.aspectDescriptors = aspects.stream().map(Aspect::getDescriptor).collect(toImmutableList()); this.mainAspectPrerequisites = mainAspectPrerequisites; + this.baseTargetToolchainContexts = baseTargetToolchainContexts; + this.targetUsesAutoExecGroups = targetUsesAutoExecGroups; + } + + /** + * Returns the toolchain contexts for the base target. Can be null if no aspect in the {@code + * aspects} path propagate to the toolchains. + */ + @Nullable + public ToolchainCollection<AspectBaseTargetResolvedToolchainContext> + getBaseTargetToolchainContexts() { + return baseTargetToolchainContexts; + } + + /** Returns the labels of default the toolchain types that aspects have propagated. */ + public ImmutableSet<Label> getRequestedToolchainTypesLabels() { + if (targetUsesAutoExecGroups) { + return baseTargetToolchainContexts.getContextMap().entrySet().stream() + .filter(e -> isAutomaticExecGroup(e.getKey())) + .flatMap(e -> e.getValue().requestedToolchainTypeLabels().keySet().stream()) + .collect(toImmutableSet()); + } else { + return baseTargetToolchainContexts + .getDefaultToolchainContext() + .requestedToolchainTypeLabels() + .keySet(); + } + } + + /** + * Returns the toolchain data for the given type, or {@code null} if the toolchain type was not + * required in this context. + */ + @Nullable + public AspectBaseTargetResolvedToolchainContext.ToolchainAspectsProviders getToolchainTarget( + Label toolchainType) { + var execGroupContext = baseTargetToolchainContexts.getDefaultToolchainContext(); + if (targetUsesAutoExecGroups) { + execGroupContext = + baseTargetToolchainContexts.getContextMap().entrySet().stream() + .filter( + e -> + isAutomaticExecGroup(e.getKey()) + && e.getValue().requestedToolchainTypeLabels().containsKey(toolchainType)) + .findFirst() + .map(e -> e.getValue()) + .orElse(null); + if (execGroupContext == null) { + return null; + } + } + return execGroupContext + .getToolchains() + .get(execGroupContext.requestedToolchainTypeLabels().get(toolchainType)); } /** @@ -86,9 +159,10 @@ Builder builder, AttributeMap ruleAttributes, ImmutableListMultimap<DependencyKind, ConfiguredTargetAndData> targetsMap, - ExecGroupCollection execGroupCollection) { + ExecGroupCollection execGroupCollection, + ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts) { return createAspectContextWithSeparatedPrerequisites( - builder, ruleAttributes, targetsMap, execGroupCollection); + builder, ruleAttributes, targetsMap, execGroupCollection, baseTargetToolchainContexts); } /** @@ -99,7 +173,8 @@ RuleContext.Builder builder, AttributeMap ruleAttributes, ImmutableListMultimap<DependencyKind, ConfiguredTargetAndData> prerequisitesMap, - ExecGroupCollection execGroupCollection) { + ExecGroupCollection execGroupCollection, + ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts) { ImmutableSortedKeyListMultimap.Builder<String, ConfiguredTargetAndData> mainAspectPrerequisites = ImmutableSortedKeyListMultimap.builder(); ImmutableSortedKeyListMultimap.Builder<String, ConfiguredTargetAndData> @@ -118,6 +193,9 @@ } } + boolean targetUsesAutoExecGroups = + RuleContext.usesAutoExecGroups(ruleAttributes, builder.getConfiguration()); + return new AspectContext( builder, new AspectAwareAttributeMapper( @@ -134,7 +212,9 @@ builder.getErrorConsumer(), builder.getRule(), builder.getRuleClassNameForLogging()), - execGroupCollection); + execGroupCollection, + baseTargetToolchainContexts, + targetUsesAutoExecGroups); } private static AspectAwareAttributeMapper mergeRuleAndBaseAspectsAttributes(
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD index e0c100c..e8b84ff 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD +++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -159,6 +159,7 @@ "AnalysisResult.java", "AnalysisRootCauseEvent.java", "AnalysisUtils.java", + "AspectBaseTargetResolvedToolchainContext.java", "AspectCompleteEvent.java", "AspectContext.java", "AspectResolutionHelpers.java", @@ -322,6 +323,8 @@ ":repo_mapping_manifest_action", ":required_config_fragments_provider", ":resolved_toolchain_context", + ":resolved_toolchain_data", + ":resolved_toolchain_data_interface", ":rule_configured_object_value", ":rule_definition_environment", ":rule_error_consumer", @@ -420,6 +423,7 @@ "//src/main/java/com/google/devtools/build/lib/skyframe/serialization:visible-for-serialization", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec:serialization-constant", + "//src/main/java/com/google/devtools/build/lib/skyframe/toolchains:toolchain_context_key", "//src/main/java/com/google/devtools/build/lib/skyframe/toolchains:unloaded_toolchain_context", "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi", "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/config:configuration_transition_api", @@ -1038,8 +1042,8 @@ srcs = ["ResolvedToolchainContext.java"], deps = [ ":config/toolchain_type_requirement", + ":resolved_toolchain_data_interface", ":template_variable_info", - ":toolchain_context", "//src/main/java/com/google/devtools/build/lib/analysis/platform", "//src/main/java/com/google/devtools/build/lib/analysis/platform:utils", "//src/main/java/com/google/devtools/build/lib/cmdline", @@ -1056,6 +1060,25 @@ ) java_library( + name = "resolved_toolchain_data_interface", + srcs = ["ResolvedToolchainsDataInterface.java"], + deps = [ + ":resolved_toolchain_data", + ":toolchain_context", + "//src/main/java/com/google/devtools/build/lib/analysis/platform", + "//src/main/java/com/google/devtools/build/lib/cmdline", + "//third_party:guava", + "//third_party:jsr305", + ], +) + +java_library( + name = "resolved_toolchain_data", + srcs = ["ResolvedToolchainData.java"], + deps = ["//src/main/java/net/starlark/java/eval"], +) + +java_library( name = "run_environment_info", srcs = ["RunEnvironmentInfo.java"], deps = [ @@ -2531,6 +2554,7 @@ srcs = ["starlark/StarlarkExecGroupCollection.java"], deps = [ ":resolved_toolchain_context", + ":resolved_toolchain_data_interface", ":starlark/starlark_toolchain_context", ":toolchain_collection", "//src/main/java/com/google/devtools/build/lib/packages:exec_group", @@ -2585,6 +2609,7 @@ name = "starlark/starlark_toolchain_context", srcs = ["starlark/StarlarkToolchainContext.java"], deps = [ + ":resolved_toolchain_data", "//src/main/java/com/google/devtools/build/lib/analysis/platform", "//src/main/java/com/google/devtools/build/lib/cmdline", "//src/main/java/com/google/devtools/build/lib/packages",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java index 9339b1c..90389a5 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
@@ -602,7 +602,8 @@ OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> prerequisiteMap, ConfigConditions configConditions, @Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts, - @Nullable ToolchainCollection<ResolvedToolchainContext> baseTargetToolchainContexts, + @Nullable + ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts, @Nullable ExecGroupCollection.Builder execGroupCollectionBuilder, BuildConfigurationValue aspectConfiguration, @Nullable NestedSet<Package> transitivePackages, @@ -623,6 +624,7 @@ .setPrerequisites(removeToolchainDeps(prerequisiteMap)) .setConfigConditions(configConditions) .setToolchainContexts(toolchainContexts) + .setBaseTargetToolchainContexts(baseTargetToolchainContexts) .setExecGroupCollectionBuilder(execGroupCollectionBuilder) .setExecProperties(ImmutableMap.of()) .setRequiredConfigFragments(
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java index 45593a9..6b6a9450 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java
@@ -38,7 +38,8 @@ @AutoValue @Immutable @ThreadSafe -public abstract class ResolvedToolchainContext implements ToolchainContext { +public abstract class ResolvedToolchainContext + implements ResolvedToolchainsDataInterface<ToolchainInfo> { /** * Finishes preparing the {@link ResolvedToolchainContext} by finding the specific toolchain @@ -114,12 +115,6 @@ ImmutableSet.copyOf(toolchainTargets)); } - /** Returns a description of the target being used, for error messaging. */ - public abstract String targetDescription(); - - /** Sets the map from requested {@link Label} to toolchain type provider. */ - public abstract ImmutableMap<Label, ToolchainTypeInfo> requestedToolchainTypeLabels(); - public abstract ImmutableMap<ToolchainTypeInfo, ToolchainInfo> toolchains(); /** Returns the template variables that these toolchains provide. */ @@ -135,6 +130,7 @@ * toolchains after Automatic Exec Groups are enabled. In that case please use {@code * RuleContext.getToolchainInfo(toolchainTypeLabel)}. */ + @Override @Nullable public ToolchainInfo forToolchainType(Label toolchainTypeLabel) { ToolchainTypeInfo toolchainTypeInfo = requestedToolchainTypeLabels().get(toolchainTypeLabel);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainData.java b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainData.java new file mode 100644 index 0000000..33bcbea --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainData.java
@@ -0,0 +1,24 @@ +// Copyright 2024 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. + +package com.google.devtools.build.lib.analysis; + +import net.starlark.java.eval.StarlarkValue; + +/** + * Common interface for {@link ToolchainInfo} and {@link + * AspectBaseTargetResolvedToolchainContext.ToolchainAspectsProviders} used to provide the resolved + * toolchain data in starlark through `ctx.toolchains` and `ctx.rule.toolchains` respectively. + */ +public interface ResolvedToolchainData extends StarlarkValue {}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainsDataInterface.java b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainsDataInterface.java new file mode 100644 index 0000000..4919356 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainsDataInterface.java
@@ -0,0 +1,44 @@ +// Copyright 2024 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. + +package com.google.devtools.build.lib.analysis; + +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo; +import com.google.devtools.build.lib.cmdline.Label; +import javax.annotation.Nullable; + +/** + * Interface for resolved toolchains data. + * + * <p>This interface is used to provide toolchain data to Starlark. This data can be the {@link + * ToolchainInfo} provider as in {@link ResolvedToolchainContext} for the aspect/rule own + * toolchains, or it can be collection of aspects providers evaluated on the aspect's base target's + * toolchains as in {@link AspectBaseTargetResolvedToolchainContext}. + */ +public interface ResolvedToolchainsDataInterface<T extends ResolvedToolchainData> + extends ToolchainContext { + /** Returns a description of the target being used, for error messaging. */ + public String targetDescription(); + + /** Returns the map from requested {@link Label} to toolchain type provider. */ + public ImmutableMap<Label, ToolchainTypeInfo> requestedToolchainTypeLabels(); + + /** + * Returns the toolchain data for the given type, or {@code null} if the toolchain type was not + * required in this context. + */ + @Nullable + public T forToolchainType(Label toolchainTypeLabel); +}
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 33616df..9bb260a 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
@@ -1070,10 +1070,15 @@ } public boolean useAutoExecGroups() { - if (attributes().has("$use_auto_exec_groups")) { - return (boolean) attributes().get("$use_auto_exec_groups", Type.BOOLEAN); + return usesAutoExecGroups(attributes(), getConfiguration()); + } + + protected static boolean usesAutoExecGroups( + AttributeMap attributes, BuildConfigurationValue configuration) { + if (attributes.has("$use_auto_exec_groups")) { + return attributes.get("$use_auto_exec_groups", Type.BOOLEAN); } else { - return getConfiguration().useAutoExecGroups(); + return configuration.useAutoExecGroups(); } } @@ -1459,6 +1464,8 @@ private Mutability mutability; private NestedSet<PackageGroupContents> visibility; private ToolchainCollection<ResolvedToolchainContext> toolchainContexts; + private ToolchainCollection<AspectBaseTargetResolvedToolchainContext> + baseTargetToolchainContexts; private ExecGroupCollection.Builder execGroupCollectionBuilder; private ImmutableMap<String, String> rawExecProperties; @@ -1521,7 +1528,8 @@ if (aspects.isEmpty()) { return RuleContext.create(this, ruleAttributes, targetMap, execGroupCollection); } else { - return AspectContext.create(this, ruleAttributes, targetMap, execGroupCollection); + return AspectContext.create( + this, ruleAttributes, targetMap, execGroupCollection, baseTargetToolchainContexts); } } @@ -1639,6 +1647,20 @@ return this; } + /** + * Sets the collection of {@link AspectBaseTargetResolvedToolchainContext}s available to this + * aspect from its base target. + */ + @CanIgnoreReturnValue + public Builder setBaseTargetToolchainContexts( + ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts) { + Preconditions.checkState( + this.baseTargetToolchainContexts == null, + "baseTargetToolchainContexts has already been set for this Builder"); + this.baseTargetToolchainContexts = baseTargetToolchainContexts; + return this; + } + @CanIgnoreReturnValue public Builder setExecGroupCollectionBuilder( ExecGroupCollection.Builder execGroupCollectionBuilder) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java index 76b5430..4f64db4 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java
@@ -168,8 +168,7 @@ TransitiveInfoProviderMapBuilder nonBaseProviders = new TransitiveInfoProviderMapBuilder(); // Merge output group providers. - OutputGroupInfo mergedOutputGroupInfo = - OutputGroupInfo.merge(getAllOutputGroupProviders(base, aspects)); + OutputGroupInfo mergedOutputGroupInfo = mergeOutputGroupProviders(base, aspects); if (mergedOutputGroupInfo != null) { nonBaseProviders.put(mergedOutputGroupInfo); } @@ -237,12 +236,16 @@ return new MergedConfiguredTarget(base, aspects, nonBaseProviders.build()); } - private static ImmutableList<OutputGroupInfo> getAllOutputGroupProviders( - ConfiguredTarget base, Iterable<ConfiguredAspect> aspects) { - OutputGroupInfo baseProvider = OutputGroupInfo.get(base); + private static OutputGroupInfo mergeOutputGroupProviders( + @Nullable ConfiguredTarget base, Iterable<ConfiguredAspect> aspects) + throws DuplicateException { ImmutableList.Builder<OutputGroupInfo> providers = ImmutableList.builder(); - if (baseProvider != null) { - providers.add(baseProvider); + + if (base != null) { + OutputGroupInfo baseProvider = OutputGroupInfo.get(base); + if (baseProvider != null) { + providers.add(baseProvider); + } } for (ConfiguredAspect configuredAspect : aspects) { @@ -252,7 +255,7 @@ } providers.add(aspectProvider); } - return providers.build(); + return OutputGroupInfo.merge(providers.build()); } private static ImmutableList<NestedSet<AnalysisFailure>> getAnalysisFailures( @@ -316,4 +319,43 @@ public ConfiguredTarget unwrapIfMerged() { return base.unwrapIfMerged(); } + + /** Returns only the providers from the aspects. */ + public TransitiveInfoProviderMap getAspectsProviders() throws DuplicateException { + TransitiveInfoProviderMapBuilder aspectsProviders = new TransitiveInfoProviderMapBuilder(); + + // Merge output group providers of aspects only. Filtering the base target output + // groups from `nonBaseProviders` does not work because some groups like + // `OutputGroupInfo#Validation` contains artifacts from both base + // target and aspects. + var outputGroups = mergeOutputGroupProviders(/* base= */ null, aspects); + if (outputGroups != null) { + aspectsProviders.put(outputGroups); + } + + // Merge other aspects providers. + for (int i = 0; i < nonBaseProviders.getProviderCount(); ++i) { + Object providerKey = nonBaseProviders.getProviderKeyAt(i); + if (OutputGroupInfo.STARLARK_CONSTRUCTOR.getKey().equals(providerKey) + || AnalysisFailureInfo.STARLARK_CONSTRUCTOR.getKey().equals(providerKey) + || ExtraActionArtifactsProvider.class.equals(providerKey) + || RequiredConfigFragmentsProvider.class.equals(providerKey)) { + continue; + } + + if (providerKey instanceof Class<?>) { + @SuppressWarnings("unchecked") + Class<? extends TransitiveInfoProvider> providerClass = + (Class<? extends TransitiveInfoProvider>) providerKey; + aspectsProviders.put( + providerClass, (TransitiveInfoProvider) nonBaseProviders.getProviderInstanceAt(i)); + } else if (providerKey instanceof String legacyId) { + aspectsProviders.put(legacyId, nonBaseProviders.getProviderInstanceAt(i)); + } else if (providerKey instanceof Provider.Key key) { + aspectsProviders.put((Info) nonBaseProviders.getProviderInstanceAt(i)); + } + } + + return aspectsProviders.build(); + } }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD index ca9668e..6df3cdb 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD +++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/BUILD
@@ -25,6 +25,7 @@ ), deps = [ "//src/main/java/com/google/devtools/build/lib/analysis:config/config_matching_provider", + "//src/main/java/com/google/devtools/build/lib/analysis:resolved_toolchain_data", "//src/main/java/com/google/devtools/build/lib/analysis:transitive_info_provider", "//src/main/java/com/google/devtools/build/lib/cmdline", "//src/main/java/com/google/devtools/build/lib/concurrent",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java index 9f88d0e..7993b3a 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/ToolchainInfo.java
@@ -17,6 +17,7 @@ import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; +import com.google.devtools.build.lib.analysis.ResolvedToolchainData; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.BuiltinProvider; @@ -38,7 +39,8 @@ * additional fields to Starlark code. Also, these are not disjoint. */ @Immutable -public final class ToolchainInfo extends NativeInfo implements ToolchainInfoApi { +public final class ToolchainInfo extends NativeInfo + implements ToolchainInfoApi, ResolvedToolchainData { /** Name used in Starlark for accessing this provider. */ public static final String STARLARK_NAME = "ToolchainInfo";
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkAttributesCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkAttributesCollection.java index 8166715..609fccb 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkAttributesCollection.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkAttributesCollection.java
@@ -16,6 +16,7 @@ import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.AliasProvider; +import com.google.devtools.build.lib.analysis.AspectContext; import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts; import com.google.devtools.build.lib.analysis.PrerequisitesCollection; @@ -29,6 +30,8 @@ import com.google.devtools.build.lib.packages.Type; import com.google.devtools.build.lib.packages.Type.LabelClass; import com.google.devtools.build.lib.starlarkbuildapi.StarlarkAttributesCollectionApi; +import com.google.devtools.build.lib.starlarkbuildapi.platform.ExecGroupCollectionApi; +import com.google.devtools.build.lib.starlarkbuildapi.platform.ToolchainContextApi; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -116,6 +119,36 @@ return ruleClassName; } + @Override + public ToolchainContextApi toolchains() throws EvalException { + checkMutable("toolchains"); + if (((AspectContext) starlarkRuleContext.getRuleContext()).getBaseTargetToolchainContexts() + == null) { + return StarlarkToolchainContext.TOOLCHAINS_NOT_VALID; + } + var aspectContext = ((AspectContext) starlarkRuleContext.getRuleContext()); + + return StarlarkToolchainContext.create( + aspectContext + .getBaseTargetToolchainContexts() + .getDefaultToolchainContext() + .targetDescription(), + /* resolveToolchainDataFunc= */ aspectContext::getToolchainTarget, + /* resolvedToolchainTypeLabels= */ aspectContext.getRequestedToolchainTypesLabels()); + } + + @Override + public ExecGroupCollectionApi execGroups() throws EvalException { + checkMutable("exec_groups"); + if (((AspectContext) starlarkRuleContext.getRuleContext()).getBaseTargetToolchainContexts() + == null) { + return StarlarkExecGroupCollection.EXEC_GRPOUP_COLLECTION_NOT_VALID; + } + // Create a thin wrapper around the toolchain collection, to expose the Starlark API. + return StarlarkExecGroupCollection.create( + ((AspectContext) starlarkRuleContext.getRuleContext()).getBaseTargetToolchainContexts()); + } + public ImmutableMap<Artifact, FilesToRunProvider> getExecutableRunfilesMap() { return executableRunfilesMap; }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkExecGroupCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkExecGroupCollection.java index f75eb9e..8c63d98 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkExecGroupCollection.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkExecGroupCollection.java
@@ -19,6 +19,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.ResolvedToolchainContext; +import com.google.devtools.build.lib.analysis.ResolvedToolchainsDataInterface; import com.google.devtools.build.lib.analysis.ToolchainCollection; import com.google.devtools.build.lib.starlarkbuildapi.platform.ExecGroupCollectionApi; import com.google.devtools.build.lib.starlarkbuildapi.platform.ToolchainContextApi; @@ -39,18 +40,37 @@ public abstract class StarlarkExecGroupCollection implements ExecGroupCollectionApi { /** + * Empty collection of exec groups to be used when exec groups are not valid in the current + * context. + */ + public static final ExecGroupCollectionApi EXEC_GRPOUP_COLLECTION_NOT_VALID = + new ExecGroupCollectionApi() { + @Override + public boolean containsKey(StarlarkSemantics semantics, Object key) { + return false; + } + + @Override + public Object getIndex(StarlarkSemantics semantics, Object key) throws EvalException { + throw Starlark.errorf("exec_groups are not valid in this context"); + } + }; + + /** * Returns a new {@link StarlarkExecGroupCollection} backed by the given {@code * toolchainCollection}. */ public static StarlarkExecGroupCollection create( - ToolchainCollection<ResolvedToolchainContext> toolchainCollection) { + ToolchainCollection<? extends ResolvedToolchainsDataInterface<?>> toolchainCollection) { return new AutoValue_StarlarkExecGroupCollection(toolchainCollection); } - protected abstract ToolchainCollection<ResolvedToolchainContext> toolchainCollection(); + protected abstract ToolchainCollection<? extends ResolvedToolchainsDataInterface<?>> + toolchainCollection(); @VisibleForTesting - public ImmutableMap<String, ResolvedToolchainContext> getToolchainCollectionForTesting() { + public ImmutableMap<String, ? extends ResolvedToolchainsDataInterface<?>> + getToolchainCollectionForTesting() { return toolchainCollection().getContextMap(); } @@ -82,8 +102,7 @@ String.join(", ", getScrubbedExecGroups())); } - ResolvedToolchainContext toolchainContext = - toolchainCollection().getToolchainContext(execGroup); + var toolchainContext = toolchainCollection().getToolchainContext(execGroup); if (toolchainContext == null) { return new AutoValue_StarlarkExecGroupCollection_StarlarkExecGroupContext( StarlarkToolchainContext.TOOLCHAINS_NOT_VALID); @@ -92,7 +111,7 @@ ToolchainContextApi starlarkToolchainContext = StarlarkToolchainContext.create( /* targetDescription= */ toolchainContext.targetDescription(), - /* resolveToolchainInfoFunc= */ toolchainContext::forToolchainType, + /* resolveToolchainDataFunc= */ toolchainContext::forToolchainType, /* resolvedToolchainTypeLabels= */ toolchainContext .requestedToolchainTypeLabels() .keySet());
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java index 6463a73..065075c 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkToolchainContext.java
@@ -18,7 +18,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; -import com.google.devtools.build.lib.analysis.platform.ToolchainInfo; +import com.google.devtools.build.lib.analysis.ResolvedToolchainData; import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; @@ -56,19 +56,19 @@ public static ToolchainContextApi create( String targetDescription, - Function<Label, ToolchainInfo> resolveToolchainInfoFunc, + Function<Label, ResolvedToolchainData> resolveToolchainDataFunc, ImmutableSet<Label> resolvedToolchainTypeLabels) { Preconditions.checkNotNull(targetDescription); - Preconditions.checkNotNull(resolveToolchainInfoFunc); + Preconditions.checkNotNull(resolveToolchainDataFunc); Preconditions.checkNotNull(resolvedToolchainTypeLabels); return new AutoValue_StarlarkToolchainContext( - targetDescription, resolveToolchainInfoFunc, resolvedToolchainTypeLabels); + targetDescription, resolveToolchainDataFunc, resolvedToolchainTypeLabels); } protected abstract String targetDescription(); - protected abstract Function<Label, ToolchainInfo> resolveToolchainInfoFunc(); + protected abstract Function<Label, ResolvedToolchainData> resolveToolchainFunc(); protected abstract ImmutableSet<Label> resolvedToolchainTypeLabels(); @@ -120,7 +120,7 @@ toolchainTypeLabel, resolvedToolchainTypeLabels().stream().map(Label::toString).collect(joining(", "))); } - ToolchainInfo toolchainInfo = resolveToolchainInfoFunc().apply(toolchainTypeLabel); + var toolchainInfo = resolveToolchainFunc().apply(toolchainTypeLabel); if (toolchainInfo == null) { return Starlark.NONE; }
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 ce38972..786e1f9 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
@@ -20,11 +20,13 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.devtools.build.lib.actions.ActionConflictException; import com.google.devtools.build.lib.actions.ActionLookupKey; import com.google.devtools.build.lib.analysis.AliasProvider; +import com.google.devtools.build.lib.analysis.AspectBaseTargetResolvedToolchainContext; import com.google.devtools.build.lib.analysis.AspectValue; import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment; import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment.MissingDepException; @@ -48,6 +50,7 @@ import com.google.devtools.build.lib.analysis.config.StarlarkExecTransitionLoader; import com.google.devtools.build.lib.analysis.config.StarlarkExecTransitionLoader.StarlarkExecTransitionLoadingException; import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget; +import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo; import com.google.devtools.build.lib.analysis.producers.DependencyContext; import com.google.devtools.build.lib.analysis.producers.DependencyContextProducer; import com.google.devtools.build.lib.analysis.producers.UnloadedToolchainContextsInputs; @@ -417,11 +420,16 @@ } toolchainContexts = contextsBuilder.build(); } - - // TODO(b/288421584): In the following step, load the base target resolved toolchains targets - // and pass them to the AspectContext. - ToolchainCollection<ResolvedToolchainContext> baseTargetToolchainContexts = null; - + ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts; + try { + baseTargetToolchainContexts = + getBaseTargetToolchainContexts( + baseTargetUnloadedToolchainContexts, aspect, target, depValueMap); + } catch (DuplicateException e) { + env.getListener().handle(Event.error(target.getLocation(), e.getMessage())); + throw new AspectFunctionException( + new AspectCreationException(e.getMessage(), target.getLabel(), configuration)); + } return createAspect( env, key, @@ -468,6 +476,54 @@ } /** + * Returns the {@link ToolchainCollection} of {@link AspectBaseTargetResolvedToolchainContext}s + * for the base target. + */ + @Nullable + private static ToolchainCollection<AspectBaseTargetResolvedToolchainContext> + getBaseTargetToolchainContexts( + ToolchainCollection<UnloadedToolchainContext> baseTargetUnloadedToolchainContexts, + Aspect aspect, + Target target, + OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> depValueMap) + throws DuplicateException { + if (baseTargetUnloadedToolchainContexts == null) { + return null; + } + String description = + "aspect " + aspect.getDescriptor().getDescription() + " applied to " + target; + + ToolchainCollection.Builder<AspectBaseTargetResolvedToolchainContext> targetContextsBuilder = + ToolchainCollection.builder(); + + for (Map.Entry<String, UnloadedToolchainContext> unloadedContext : + baseTargetUnloadedToolchainContexts.getContextMap().entrySet()) { + // For each requested toolchain type, collect the targets of its resolved toolchains. If + // multiple types are resolved to the same toolchain, the `ConfiguredTargetAndData` + // of the toolchain can be different for each of them depending on the aspects + // propagating to each toolchain type. + ImmutableMultimap.Builder<ToolchainTypeInfo, ConfiguredTargetAndData> toolchainsDeps = + ImmutableMultimap.builder(); + + for (var toolchainTypeInfo : unloadedContext.getValue().toolchainTypeToResolved().keySet()) { + toolchainsDeps.putAll( + toolchainTypeInfo, + ImmutableSet.copyOf( + depValueMap.get( + DependencyKind.forBaseTargetExecGroup( + unloadedContext.getKey(), toolchainTypeInfo.typeLabel())))); + } + + targetContextsBuilder.addContext( + unloadedContext.getKey(), + AspectBaseTargetResolvedToolchainContext.load( + unloadedContext.getValue(), description, toolchainsDeps.build())); + } + + return targetContextsBuilder.build(); + } + + /** * Returns the {@link ToolchainCollection} of {@link UnloadedToolchainContext}s for the base * target. */ @@ -868,7 +924,8 @@ BuildConfigurationValue configuration, ConfigConditions configConditions, @Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts, - @Nullable ToolchainCollection<ResolvedToolchainContext> baseTargetToolchainContexts, + @Nullable + ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts, @Nullable ExecGroupCollection.Builder execGroupCollectionBuilder, OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> directDeps, TransitiveDependencyState transitiveState,
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkAttributesCollectionApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkAttributesCollectionApi.java index 208f2e0..70d8b8a 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkAttributesCollectionApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkAttributesCollectionApi.java
@@ -16,6 +16,8 @@ import com.google.devtools.build.docgen.annot.DocCategory; import com.google.devtools.build.lib.starlarkbuildapi.core.StructApi; +import com.google.devtools.build.lib.starlarkbuildapi.platform.ExecGroupCollectionApi; +import com.google.devtools.build.lib.starlarkbuildapi.platform.ToolchainContextApi; import net.starlark.java.annot.StarlarkBuiltin; import net.starlark.java.annot.StarlarkMethod; import net.starlark.java.eval.EvalException; @@ -48,4 +50,18 @@ structField = true, doc = "The kind of a rule, such as 'cc_library'") String getRuleClassName() throws EvalException; + + @StarlarkMethod( + name = "toolchains", + structField = true, + doc = "Toolchains for the default exec group of the rule the aspect is applied to.") + ToolchainContextApi toolchains() throws EvalException; + + @StarlarkMethod( + name = "exec_groups", + structField = true, + doc = + "A collection of the execution groups available for the rule the aspect is applied to," + + " indexed by their names.") + ExecGroupCollectionApi execGroups() throws EvalException; }
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java index b3916c6..c20a488 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java
@@ -653,7 +653,7 @@ named = true, defaultValue = "[]", doc = - "[Currtenly no-op] List of toolchain types. The aspect propagates to target" + "Experimental: List of toolchain types. The aspect propagates to target" + " toolchains which match these toolchain types."), @Param( name = "attrs",
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform/ToolchainContextApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform/ToolchainContextApi.java index 25cad74..ff61a25 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform/ToolchainContextApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform/ToolchainContextApi.java
@@ -27,5 +27,12 @@ "Holds toolchains available for a particular exec group. Toolchain targets are accessed by" + " indexing with the toolchain type, as in" + " <code>ctx.toolchains[\"//pkg:my_toolchain_type\"]</code>. If the toolchain was" - + " optional and no toolchain was resolved, this will return <code>None</code>.") + + " optional and no toolchain was resolved, this will return <code>None</code>." + + " Accessing toolchains of an aspect or rule via" + + " <code>ctx.toolchains</code> returns the indexed toolchain as a" + + " <code>ToolchainInfo</code> provider. While when using aspects," + + " <code>ToolchainContext</code> is also used to hold the toolchains of the base" + + " target. It can be accessed by" + + " <code>ctx.rule.toolchains[\"//pkg:my_toolchain_type\"]</code> and it returns the" + + " list of providers resulted from applying the aspects on these toolchain targets. ") public interface ToolchainContextApi extends StarlarkValue, StarlarkIndexable.Threaded {}