Implement whitelisting for implicit outputs produced by CcLibrary rules
RELNOTES:none
PiperOrigin-RevId: 320348483
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 02925d8..c893f6e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -399,6 +399,7 @@
"//src/main/java/com/google/devtools/build/lib/profiler",
"//src/main/java/com/google/devtools/build/lib/profiler:google-auto-profiler-utils",
"//src/main/java/com/google/devtools/build/lib/profiler/memory:current_rule_tracker",
+ "//src/main/java/com/google/devtools/build/lib/rules/cpp:denied_implicit_outputs_marker_provider",
"//src/main/java/com/google/devtools/build/lib/shell",
"//src/main/java/com/google/devtools/build/lib/skyframe:aspect_creation_exception",
"//src/main/java/com/google/devtools/build/lib/skyframe:aspect_value_key",
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 dd0b0ec..609e30e 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
@@ -65,6 +65,7 @@
import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.profiler.memory.CurrentRuleTracker;
+import com.google.devtools.build.lib.rules.cpp.DeniedImplicitOutputMarkerProvider;
import com.google.devtools.build.lib.skyframe.AspectValueKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
@@ -85,6 +86,11 @@
*/
@ThreadSafe
public final class ConfiguredTargetFactory {
+
+ public static final String CC_LIB_IMPLICIT_OUTPUTS_ERROR =
+ "Using implicit outputs from cc_library (%s) is forbidden. Use"
+ + " the rule cc_implicit_output as an alternative.";
+
// This class is not meant to be outside of the analysis phase machinery and is only public
// in order to be accessible from the .view.skyframe package.
@@ -221,6 +227,14 @@
Optional.empty());
Verify.verifyNotNull(rule);
Artifact artifact = rule.getArtifactByOutputLabel(outputFile.getLabel());
+
+ if (rule.get(DeniedImplicitOutputMarkerProvider.PROVIDER) != null) {
+ analysisEnvironment
+ .getEventHandler()
+ .handle(Event.error(String.format(CC_LIB_IMPLICIT_OUTPUTS_ERROR, rule.getLabel())));
+ return null;
+ }
+
return new OutputFileConfiguredTarget(targetContext, outputFile, rule, artifact);
} else if (target instanceof InputFile) {
InputFile inputFile = (InputFile) target;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD b/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
index f52f810..557aa12 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
@@ -28,10 +28,13 @@
"*.java",
"transitions/*.java",
],
- exclude = INTERFACE_SOURCES,
+ exclude = INTERFACE_SOURCES + [
+ "DeniedImplicitOutputMarkerProvider.java",
+ ],
),
deps = [
":cpp_interface",
+ ":denied_implicit_outputs_marker_provider",
"//src/main/java/com/google/devtools/build/lib:syntax",
"//src/main/java/com/google/devtools/build/lib/actions",
"//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
@@ -140,3 +143,13 @@
"//third_party:jsr305",
],
)
+
+java_library(
+ name = "denied_implicit_outputs_marker_provider",
+ srcs = ["DeniedImplicitOutputMarkerProvider.java"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib/concurrent",
+ "//src/main/java/com/google/devtools/build/lib/packages",
+ "//third_party:jsr305",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index 33862d2..35ed3f8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -22,6 +22,7 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.FailAction;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
+import com.google.devtools.build.lib.analysis.Allowlist;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
@@ -77,6 +78,8 @@
/** A string constant for the name of Windows def file output group. */
public static final String DEF_FILE_OUTPUT_GROUP_NAME = "def_file";
+ public static final String IMPLICIT_OUTPUTS_ALLOWLIST = "allowed_cc_lib_implicit_outputs";
+
private final CppSemantics semantics;
protected CcLibrary(CppSemantics semantics) {
@@ -487,6 +490,16 @@
ruleContext,
ruleContext.getFragment(CppConfiguration.class),
ccCompilationOutputs));
+
+ maybeAddDeniedImplicitOutputsProvider(targetBuilder, ruleContext);
+ }
+
+ private static void maybeAddDeniedImplicitOutputsProvider(
+ RuleConfiguredTargetBuilder targetBuilder, RuleContext ruleContext) {
+ if (ruleContext.getRule().getImplicitOutputsFunction() != ImplicitOutputsFunction.NONE
+ && !Allowlist.isAvailable(ruleContext, IMPLICIT_OUTPUTS_ALLOWLIST)) {
+ targetBuilder.addNativeDeclaredProvider(new DeniedImplicitOutputMarkerProvider());
+ }
}
private static NestedSet<Artifact> collectHiddenTopLevelArtifacts(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/DeniedImplicitOutputMarkerProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/DeniedImplicitOutputMarkerProvider.java
new file mode 100644
index 0000000..f15495b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/DeniedImplicitOutputMarkerProvider.java
@@ -0,0 +1,31 @@
+// Copyright 2014 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.rules.cpp;
+
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.NativeInfo;
+import com.google.devtools.build.lib.packages.NativeProvider;
+
+/** TODO(plf): Remove once implicit outputs are removed from cc_library */
+@Immutable
+public class DeniedImplicitOutputMarkerProvider extends NativeInfo {
+ public static final NativeProvider<DeniedImplicitOutputMarkerProvider> PROVIDER =
+ new NativeProvider<DeniedImplicitOutputMarkerProvider>(
+ DeniedImplicitOutputMarkerProvider.class, "DeniedImplicitOutputMarkerProvider") {};
+
+ public DeniedImplicitOutputMarkerProvider() {
+ super(PROVIDER);
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java
index db26624..6a1ab64 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java
@@ -1633,4 +1633,56 @@
")");
checkError("//foo", "Trying to link twice");
}
+
+ @Test
+ public void testImplicitOutputsWhitelistNotOnWhitelist() throws Exception {
+ if (analysisMock.isThisBazel()) {
+ return;
+ }
+ scratch.overwriteFile(
+ "tools/build_defs/cc/whitelists/cc_lib_implicit_outputs/BUILD",
+ "package_group(",
+ " name = 'allowed_cc_lib_implicit_outputs',",
+ " packages = [])");
+
+ scratch.file(
+ "foo/BUILD",
+ "filegroup(",
+ " name = 'denied',",
+ " srcs = [':libdenied_cc_lib.a'],",
+ ")",
+ "cc_library(",
+ " name = 'denied_cc_lib',",
+ " srcs = ['denied_cc_lib.cc'],",
+ ")");
+ checkError(
+ "//foo:denied",
+ "Using implicit outputs from cc_library (//foo:denied_cc_lib) is "
+ + "forbidden. Use the rule cc_implicit_output as an alternative.");
+ }
+
+ @Test
+ public void testImplicitOutputsWhitelistOnWhitelist() throws Exception {
+ if (analysisMock.isThisBazel()) {
+ return;
+ }
+ scratch.overwriteFile(
+ "tools/build_defs/cc/whitelists/cc_lib_implicit_outputs/BUILD",
+ "package_group(",
+ " name = 'allowed_cc_lib_implicit_outputs',",
+ " packages = ['//bar'])");
+
+ scratch.file(
+ "bar/BUILD",
+ "filegroup(",
+ " name = 'allowed',",
+ " srcs = [':liballowed_cc_lib.a'],",
+ ")",
+ "cc_library(",
+ " name = 'allowed_cc_lib',",
+ " srcs = ['allowed_cc_lib.cc'],",
+ ")");
+ getConfiguredTarget("//bar:allowed");
+ assertNoEvents();
+ }
}