From 6d71850f6d5e9989826114395d58377769f44e4b Mon Sep 17 00:00:00 2001 From: Philipp Schrader Date: Fri, 22 Jul 2022 12:23:16 -0700 Subject: [PATCH] Prevent aspects from executing on incompatible targets This patch prevents aspect functions from being evaluated when their associated targets are incompatible. Otherwise aspects can generate errors that should never be printed at all. For example, an aspect evaluating an incompatible target may generate errors about missing providers. This is not the desired behaviour. The implementation in this patch short-circuits the `AspectValue` creation if the associated target is incompatible. I had tried to add an `IncompatiblePlatformProvider` to the corresponding `ConfiguredAspect` instance, but then Bazel complained about having duplicate `IncompatiblePlatformProvider` instances. Fixes #15271 Closes #15426. PiperOrigin-RevId: 462678126 Change-Id: I6cd6d4d9936bb1dde6a1282399ed4adc389ceed1 --- .../build/lib/skyframe/AspectFunction.java | 13 ++ .../google/devtools/build/lib/skyframe/BUILD | 1 + .../target_compatible_with_test.sh | 159 ++++++++++++++++++ 3 files changed, 173 insertions(+) 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 4d82e0b9601882..45eb7affc51ade 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 @@ -38,6 +38,7 @@ import com.google.devtools.build.lib.analysis.DuplicateException; import com.google.devtools.build.lib.analysis.ExecGroupCollection; import com.google.devtools.build.lib.analysis.ExecGroupCollection.InvalidExecGroupException; +import com.google.devtools.build.lib.analysis.IncompatiblePlatformProvider; import com.google.devtools.build.lib.analysis.InconsistentAspectOrderException; import com.google.devtools.build.lib.analysis.ResolvedToolchainContext; import com.google.devtools.build.lib.analysis.TargetAndConfiguration; @@ -191,6 +192,18 @@ public SkyValue compute(SkyKey skyKey, Environment env) ConfiguredTarget associatedTarget = state.initialValues.associatedTarget; Target target = state.initialValues.target; + // If the target is incompatible, then there's not much to do. The intent here is to create an + // AspectValue that doesn't trigger any of the associated target's dependencies to be evaluated + // against this aspect. + if (associatedTarget.get(IncompatiblePlatformProvider.PROVIDER) != null) { + return new AspectValue( + key, + aspect, + target.getLocation(), + ConfiguredAspect.forNonapplicableTarget(), + state.transitivePackagesForPackageRootResolution.build()); + } + if (AliasProvider.isAlias(associatedTarget)) { return createAliasAspect( env, diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD index 91324bb4ac362f..549485b6e78091 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD @@ -261,6 +261,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:dependency_kind", "//src/main/java/com/google/devtools/build/lib/analysis:duplicate_exception", "//src/main/java/com/google/devtools/build/lib/analysis:exec_group_collection", + "//src/main/java/com/google/devtools/build/lib/analysis:incompatible_platform_provider", "//src/main/java/com/google/devtools/build/lib/analysis:inconsistent_aspect_order_exception", "//src/main/java/com/google/devtools/build/lib/analysis:platform_configuration", "//src/main/java/com/google/devtools/build/lib/analysis:platform_options", diff --git a/src/test/shell/integration/target_compatible_with_test.sh b/src/test/shell/integration/target_compatible_with_test.sh index e2bf1d1f2685c0..c9e83de68c36e9 100755 --- a/src/test/shell/integration/target_compatible_with_test.sh +++ b/src/test/shell/integration/target_compatible_with_test.sh @@ -1082,4 +1082,163 @@ function test_aquery_incompatible_target() { expect_log "target platform (//target_skipping:foo3_platform) didn't satisfy constraint //target_skipping:foo1" } +# Use aspects to interact with incompatible targets and validate the behaviour. +function test_aspect_skipping() { + cat >> target_skipping/BUILD < target_skipping/defs.bzl < "${TEST_log}" \ + || fail "Bazel failed unexpectedly." + expect_log "${debug_message1}" + expect_log "${debug_message2}" + expect_log "${debug_message3}" + expect_log "${debug_message4}" + expect_not_log "${debug_message5}" + # Invert the compatibility and validate that aspects run on the other targets + # now. + bazel build \ + --show_result=10 \ + --host_platform=@//target_skipping:foo1_bar1_platform \ + --platforms=@//target_skipping:foo1_bar1_platform \ + //target_skipping:all &> "${TEST_log}" \ + || fail "Bazel failed unexpectedly." + expect_not_log "${debug_message1}" + expect_not_log "${debug_message2}" + expect_not_log "${debug_message3}" + expect_not_log "${debug_message4}" + expect_log "${debug_message5}" + # Validate that explicitly trying to build a target with an aspect against an + # incompatible target produces the normal error message. + bazel build \ + --show_result=10 \ + --host_platform=@//target_skipping:foo1_bar1_platform \ + --platforms=@//target_skipping:foo1_bar1_platform \ + //target_skipping:twice_inspected_foo3_target &> "${TEST_log}" \ + && fail "Bazel passed unexpectedly." + # TODO(#15427): Should use expect_log_once here when the issue is fixed. + expect_log 'ERROR: Target //target_skipping:twice_inspected_foo3_target is incompatible and cannot be built, but was explicitly requested.' + expect_log '^Dependency chain:$' + expect_log '^ //target_skipping:twice_inspected_foo3_target ' + expect_log '^ //target_skipping:previously_inspected_basic_target ' + expect_log '^ //target_skipping:inspected_foo3_target ' + expect_log '^ //target_skipping:aliased_other_basic_target ' + expect_log '^ //target_skipping:other_basic_target ' + expect_log " //target_skipping:basic_foo3_target .* <-- target platform (//target_skipping:foo1_bar1_platform) didn't satisfy constraint //target_skipping:foo3:" + expect_log 'FAILED: Build did NOT complete successfully' + expect_not_log "${debug_message1}" + expect_not_log "${debug_message2}" + expect_not_log "${debug_message3}" + expect_not_log "${debug_message4}" + expect_not_log "${debug_message5}" +} + run_suite "target_compatible_with tests"