diff --git a/site/docs/platforms.md b/site/docs/platforms.md index 9d6466201548ee..2dbc583201eddf 100644 --- a/site/docs/platforms.md +++ b/site/docs/platforms.md @@ -225,3 +225,26 @@ cc_library( ) ``` +### Detecting incompatible targets using `bazel cquery` + +You can use the +[`IncompatiblePlatformProvider`](skylark/lib/IncompatiblePlatformProvider.html) +in `bazel cquery`'s [Starlark output +format](cquery.html#defining-the-output-format-using-starlark) to distinguish +incompatible targets from compatible ones. + +This can be used to filter out incompatible targets. The example below will +only print the labels for targets that are compatible. Incompatible targets are +not printed. + +```console +$ cat example.cquery + +def format(target): + if "IncompatiblePlatformProvider" not in providers(target): + return target.label + return "" + + +$ bazel cquery //... --output=starlark --starlark:file=example.cquery +``` 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 52ef94a4d78caa..6344f7300eefd5 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD +++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD @@ -797,8 +797,10 @@ java_library( srcs = ["IncompatiblePlatformProvider.java"], deps = [ ":configured_target", - ":transitive_info_provider", "//src/main/java/com/google/devtools/build/lib/analysis/platform", + "//src/main/java/com/google/devtools/build/lib/concurrent", + "//src/main/java/com/google/devtools/build/lib/packages", + "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform", "//third_party:auto_value", "//third_party:guava", "//third_party:jsr305", diff --git a/src/main/java/com/google/devtools/build/lib/analysis/IncompatiblePlatformProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/IncompatiblePlatformProvider.java index da72929f6c384c..ca5377457f2b28 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/IncompatiblePlatformProvider.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/IncompatiblePlatformProvider.java @@ -18,6 +18,10 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.BuiltinProvider; +import com.google.devtools.build.lib.packages.Info; +import com.google.devtools.build.lib.starlarkbuildapi.platform.IncompatiblePlatformProviderApi; import javax.annotation.Nullable; /** @@ -34,8 +38,23 @@ * target is incompatible because one of its dependencies is incompatible, then all the incompatible * dependencies are available via {@code getTargetResponsibleForIncompatibility()}. */ +@Immutable @AutoValue -public abstract class IncompatiblePlatformProvider implements TransitiveInfoProvider { +public abstract class IncompatiblePlatformProvider + implements Info, IncompatiblePlatformProviderApi { + /** Name used in Starlark for accessing this provider. */ + public static final String STARLARK_NAME = "IncompatiblePlatformProvider"; + + /** Provider singleton constant. */ + public static final BuiltinProvider PROVIDER = + new BuiltinProvider( + STARLARK_NAME, IncompatiblePlatformProvider.class) {}; + + @Override + public BuiltinProvider getProvider() { + return PROVIDER; + } + public static IncompatiblePlatformProvider incompatibleDueToTargets( ImmutableList targetsResponsibleForIncompatibility) { Preconditions.checkNotNull(targetsResponsibleForIncompatibility); @@ -50,6 +69,11 @@ public static IncompatiblePlatformProvider incompatibleDueToConstraints( return new AutoValue_IncompatiblePlatformProvider(null, constraints); } + @Override + public boolean isImmutable() { + return true; // immutable and Starlark-hashable + } + /** * Returns the incompatible dependencies that caused this provider to be present. * 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 bb94ee44debd30..580a336d2b6c96 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 @@ -880,7 +880,7 @@ public static IncompatibleCheckResult checkForIncompatibility(ConfiguredTarget t target = ((OutputFileConfiguredTarget) target).getGeneratingRule(); } return IncompatibleCheckResult.create( - target.getProvider(IncompatiblePlatformProvider.class) != null, target); + target.get(IncompatiblePlatformProvider.PROVIDER) != null, target); } /** @@ -996,13 +996,11 @@ private static ConfiguredTarget createIncompatibleConfiguredTarget( builder.setFilesToBuild(filesToBuild); if (targetsResponsibleForIncompatibility != null) { - builder.add( - IncompatiblePlatformProvider.class, + builder.addNativeDeclaredProvider( IncompatiblePlatformProvider.incompatibleDueToTargets( targetsResponsibleForIncompatibility)); } else if (violatedConstraints != null) { - builder.add( - IncompatiblePlatformProvider.class, + builder.addNativeDeclaredProvider( IncompatiblePlatformProvider.incompatibleDueToConstraints(violatedConstraints)); } else { throw new IllegalArgumentException( diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java index 539d988076df54..b17a40d543b554 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java @@ -195,7 +195,7 @@ private static String reportOnIncompatibility(ConfiguredTarget target) { // save the user bazel round trips. while (target != null) { message += "\n " + target.getLabel(); - provider = target.getProvider(IncompatiblePlatformProvider.class); + provider = target.get(IncompatiblePlatformProvider.PROVIDER); ImmutableList targetList = provider.targetsResponsibleForIncompatibility(); if (targetList == null) { target = null; diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform/IncompatiblePlatformProviderApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform/IncompatiblePlatformProviderApi.java new file mode 100644 index 00000000000000..624d6c14d3c9e5 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/platform/IncompatiblePlatformProviderApi.java @@ -0,0 +1,30 @@ +// Copyright 2021 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.starlarkbuildapi.platform; + +import com.google.devtools.build.docgen.annot.DocCategory; +import net.starlark.java.annot.StarlarkBuiltin; +import net.starlark.java.eval.StarlarkValue; + +/** Targets that are incompatible with the target platform. */ +@StarlarkBuiltin( + name = "IncompatiblePlatformProvider", + doc = + "A provider for targets that are incompatible with the target platform. See " + + "" + + "Detecting incompatible targets using bazel cquery for more " + + "information.", + category = DocCategory.PROVIDER) +public interface IncompatiblePlatformProviderApi extends StarlarkValue {} diff --git a/src/test/shell/integration/target_compatible_with_test.sh b/src/test/shell/integration/target_compatible_with_test.sh index b79f1ba5a869d9..375ca2a43561b9 100755 --- a/src/test/shell/integration/target_compatible_with_test.sh +++ b/src/test/shell/integration/target_compatible_with_test.sh @@ -912,6 +912,44 @@ function test_cquery_incompatible_target() { expect_log "target platform didn't satisfy constraint //target_skipping:foo1" } +# Runs a cquery and makes sure that we can properly distinguish between +# incompatible targets and compatible targets. +function test_cquery_with_starlark_formatting() { + cat > target_skipping/compatibility.cquery < "${TEST_log}" + + expect_log '^//target_skipping:pass_on_foo1 is compatible$' + expect_log '^//target_skipping:fail_on_foo2 is incompatible$' + expect_log '^//target_skipping:some_foo3_target is incompatible$' + + bazel cquery \ + --host_platform=//target_skipping:foo3_platform \ + --platforms=//target_skipping:foo3_platform \ + :all \ + --output=starlark --starlark:file=target_skipping/compatibility.cquery \ + &> "${TEST_log}" + + expect_log '^//target_skipping:pass_on_foo1 is incompatible$' + expect_log '^//target_skipping:fail_on_foo2 is incompatible$' + expect_log '^//target_skipping:some_foo3_target is compatible$' +} + # Run an aquery on a target that is compatible. This should pass. function test_aquery_compatible_target() { write_query_test_targets