Optionally propagate aspects through rule output dependencies
Starlark-defined aspects can opt into this new feature by being defined with a new parameter on the aspect() function, "apply_to_generating_rules".
This behavior is guarded by a new experimental flag, --experimental_aspect_output_propagation.
RELNOTES: None.
PiperOrigin-RevId: 269571978
diff --git a/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java b/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java
index bbe9db3..35e02b2 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/AspectDefinition.java
@@ -75,6 +75,7 @@
@Nullable private final ImmutableSet<String> restrictToAttributes;
@Nullable private final ConfigurationFragmentPolicy configurationFragmentPolicy;
private final boolean applyToFiles;
+ private final boolean applyToGeneratingRules;
public AdvertisedProviderSet getAdvertisedProviders() {
return advertisedProviders;
@@ -90,7 +91,8 @@
ImmutableSet<Label> requiredToolchains,
@Nullable ImmutableSet<String> restrictToAttributes,
@Nullable ConfigurationFragmentPolicy configurationFragmentPolicy,
- boolean applyToFiles) {
+ boolean applyToFiles,
+ boolean applyToGeneratingRules) {
this.aspectClass = aspectClass;
this.advertisedProviders = advertisedProviders;
this.requiredProviders = requiredProviders;
@@ -101,6 +103,7 @@
this.restrictToAttributes = restrictToAttributes;
this.configurationFragmentPolicy = configurationFragmentPolicy;
this.applyToFiles = applyToFiles;
+ this.applyToGeneratingRules = applyToGeneratingRules;
}
public String getName() {
@@ -169,6 +172,14 @@
return applyToFiles;
}
+ /**
+ * Returns whether this aspect should, when it would be applied to an output file, instead apply
+ * to the generating rule of that output file.
+ */
+ public boolean applyToGeneratingRules() {
+ return applyToGeneratingRules;
+ }
+
public static boolean satisfies(Aspect aspect, AdvertisedProviderSet advertisedProviderSet) {
return aspect.getDefinition().getRequiredProviders().isSatisfiedBy(advertisedProviderSet);
}
@@ -234,6 +245,7 @@
private final ConfigurationFragmentPolicy.Builder configurationFragmentPolicy =
new ConfigurationFragmentPolicy.Builder();
private boolean applyToFiles = false;
+ private boolean applyToGeneratingRules = false;
private final List<Label> requiredToolchains = new ArrayList<>();
public Builder(AspectClass aspectClass) {
@@ -259,7 +271,7 @@
requiredProviders.addNativeSet(ImmutableSet.copyOf(providers));
return this;
}
-
+
/**
* Asserts that this aspect can only be evaluated for rules that supply all of the specified
* Skylark providers.
@@ -456,6 +468,18 @@
return this;
}
+ /**
+ * Sets whether this aspect should, when it would be applied to an output file, instead apply to
+ * the generating rule of that output file.
+ *
+ * <p>Default is <code>false</code>. Currently only supported for aspects which do not have a
+ * "required providers" list.
+ */
+ public Builder applyToGeneratingRules(boolean applyToGeneratingRules) {
+ this.applyToGeneratingRules = applyToGeneratingRules;
+ return this;
+ }
+
/** Adds the given toolchains as requirements for this aspect. */
public Builder addRequiredToolchains(Label... toolchainLabels) {
Iterables.addAll(this.requiredToolchains, Lists.newArrayList(toolchainLabels));
@@ -473,16 +497,24 @@
* <p>The builder object is reusable afterwards.
*/
public AspectDefinition build() {
+ RequiredProviders requiredProviders = this.requiredProviders.build();
+ if (applyToGeneratingRules && !requiredProviders.acceptsAny()) {
+ throw new IllegalStateException(
+ "An aspect cannot simultaneously have required providers "
+ + "and apply to generating rules.");
+ }
+
return new AspectDefinition(
aspectClass,
advertisedProviders.build(),
- requiredProviders.build(),
+ requiredProviders,
requiredAspectProviders.build(),
ImmutableMap.copyOf(attributes),
ImmutableSet.copyOf(requiredToolchains),
propagateAlongAttributes == null ? null : ImmutableSet.copyOf(propagateAlongAttributes),
configurationFragmentPolicy.build(),
- applyToFiles);
+ applyToFiles,
+ applyToGeneratingRules);
}
}
}