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;
}