Allow attributes to indicate whether they are for tools or not.
This allows common attributes like `target_compatible_with` to indicate that they do not create real dependencies on the targets pointed to.
PiperOrigin-RevId: 375559104
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
index 612867c..0b7de92 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
@@ -387,6 +387,9 @@
attr(RuleClass.TARGET_COMPATIBLE_WITH_ATTR, LABEL_LIST)
.mandatoryProviders(ConstraintValueInfo.PROVIDER.id())
// This should be configurable to allow for complex types of restrictions.
+ .tool(
+ "target_compatible_with exists for constraint checking, not to create an"
+ + " actual dependency")
.allowedFileTypes(FileTypeSet.NO_FILE))
.build();
}
@@ -447,6 +450,9 @@
attr(RuleClass.EXEC_COMPATIBLE_WITH_ATTR, BuildType.LABEL_LIST)
.allowedFileTypes()
.nonconfigurable("Used in toolchain resolution")
+ .tool(
+ "exec_compatible_with exists for constraint checking, not to create an"
+ + " actual dependency")
.value(ImmutableList.of()))
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
index 1c2f59f..72041e1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
@@ -348,7 +348,7 @@
// not fail the overall build, since those dependencies should have their own builds
// and tests that should surface any failing validations.
Attribute attribute = ruleContext.attributes().getAttributeDefinition(attributeName);
- if (!attribute.getTransitionFactory().isTool()
+ if (!attribute.isToolDependency()
&& !attribute.isImplicit()
&& attribute.getType().getLabelClass() == LabelClass.DEPENDENCY) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/RuleContextConstraintSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/RuleContextConstraintSemantics.java
index ff38aa8..30086f7 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/RuleContextConstraintSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/RuleContextConstraintSemantics.java
@@ -759,7 +759,7 @@
// Use the same implicit deps check that query uses. This facilitates running queries to
// determine exactly which rules need to be constraint-annotated for depot migrations.
if (!DependencyFilter.NO_IMPLICIT_DEPS.apply(ruleContext.getRule(), attrDef)
- || attrDef.getTransitionFactory().isTool()) {
+ || attrDef.isToolDependency()) {
continue;
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
index 8632c63..1e1e2ff 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleClassFunctions.java
@@ -148,11 +148,17 @@
attr(RuleClass.EXEC_COMPATIBLE_WITH_ATTR, BuildType.LABEL_LIST)
.allowedFileTypes()
.nonconfigurable("Used in toolchain resolution")
+ .tool(
+ "exec_compatible_with exists for constraint checking, not to create an"
+ + " actual dependency")
.value(ImmutableList.of()))
.add(
attr(RuleClass.TARGET_COMPATIBLE_WITH_ATTR, LABEL_LIST)
.mandatoryProviders(ConstraintValueInfo.PROVIDER.id())
// This should be configurable to allow for complex types of restrictions.
+ .tool(
+ "target_compatible_with exists for constraint checking, not to create an"
+ + " actual dependency")
.allowedFileTypes(FileTypeSet.NO_FILE))
.build();
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesCollector.java b/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesCollector.java
index 96afb5b..a8407b2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesCollector.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/InstrumentedFilesCollector.java
@@ -459,7 +459,7 @@
List<TransitiveInfoCollection> prerequisites = new ArrayList<>();
for (Attribute attr : ruleContext.getRule().getAttributes()) {
if ((attr.getType() == BuildType.LABEL_LIST || attr.getType() == BuildType.LABEL)
- && !attr.getTransitionFactory().isTool()) {
+ && !attr.isToolDependency()) {
prerequisites.addAll(ruleContext.getPrerequisites(attr.getName()));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index 5c34600..d7f4a0b 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -246,6 +246,12 @@
* analysis tests.
*/
HAS_ANALYSIS_TEST_TRANSITION,
+
+ /**
+ * Signals that a dependency attribute is used as a tool (regardless of the actual configuration
+ * or transition). Cannot be used for non-dependency attributes.
+ */
+ IS_TOOL_DEPENDENCY,
}
// TODO(bazel-team): modify this interface to extend Predicate and have an extra error
@@ -1069,6 +1075,13 @@
return setPropertyFlag(PropertyFlag.NONCONFIGURABLE, "nonconfigurable");
}
+ public Builder<TYPE> tool(String reason) {
+ Preconditions.checkState(
+ type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
+ Preconditions.checkState(!reason.isEmpty());
+ return setPropertyFlag(PropertyFlag.IS_TOOL_DEPENDENCY, "is_tool_dependency");
+ }
+
/** Returns an {@link ImmutableAttributeFactory} that can be invoked to create attributes. */
public ImmutableAttributeFactory buildPartial() {
Preconditions.checkState(
@@ -2083,6 +2096,22 @@
}
/**
+ * Returns true if this attribute is used as a tool dependency, either because the attribute
+ * declares it directly (with {@link Attribute$Builder.tool}), or because the value's {@link
+ * TransitionFactory} declares it.
+ *
+ * <p>Non-dependency attributes will always return {@code false}.
+ */
+ public boolean isToolDependency() {
+ if (getType().getLabelClass() != LabelClass.DEPENDENCY) {
+ return false;
+ }
+ if (getPropertyFlag(PropertyFlag.IS_TOOL_DEPENDENCY)) {
+ return true;
+ }
+ return getTransitionFactory().isTool();
+ }
+ /**
* Returns a predicate that evaluates to true for rule classes that are allowed labels in this
* attribute. If this is not a label or label-list attribute, the returned predicate always
* evaluates to true.
diff --git a/src/main/java/com/google/devtools/build/lib/packages/DependencyFilter.java b/src/main/java/com/google/devtools/build/lib/packages/DependencyFilter.java
index aaa4306..754847f 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/DependencyFilter.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/DependencyFilter.java
@@ -38,12 +38,7 @@
new DependencyFilter() {
@Override
public boolean apply(AttributeInfoProvider infoProvider, Attribute attribute) {
- // getConfigurationTransition() is only defined for labels which introduce a dependency.
- if (attribute.getType().getLabelClass() != LabelClass.DEPENDENCY) {
- return true;
- }
-
- return !attribute.getTransitionFactory().isTool();
+ return !attribute.isToolDependency();
}
};
/** Dependency predicate that excludes implicit dependencies */
diff --git a/src/test/shell/integration/target_compatible_with_test.sh b/src/test/shell/integration/target_compatible_with_test.sh
index 4058417..1d9feef 100755
--- a/src/test/shell/integration/target_compatible_with_test.sh
+++ b/src/test/shell/integration/target_compatible_with_test.sh
@@ -928,6 +928,20 @@
expect_log '^//target_skipping:genrule_foo1$'
}
+# Regression test for http://b/189071321: --notool_deps should exclude constraints.
+function test_query_no_tools() {
+ write_query_test_targets
+ cd target_skipping || fail "couldn't cd into workspace"
+
+ bazel query \
+ --notool_deps \
+ 'deps(//target_skipping:sh_foo1)' &> "${TEST_log}" \
+ || fail "Bazel query failed unexpectedly."
+ expect_log '^//target_skipping:sh_foo1$'
+ expect_log '^//target_skipping:genrule_foo1$'
+ expect_not_log '^//target_skipping:foo1$'
+}
+
# Run a cquery on a target that is compatible. This should pass.
function test_cquery_compatible_target() {
write_query_test_targets