diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java index 8e86b88a743123..aeb710e9c73a35 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java @@ -1179,8 +1179,7 @@ private static void addTransitiveInfoProviders( .setFilesToBuild(filesToBuild) .addNativeDeclaredProvider( CcInfo.builder().setCcCompilationContext(ccCompilationContext).build()) - .addProvider( - CcNativeLibraryProvider.class, + .addNativeDeclaredProvider( new CcNativeLibraryProvider(collectTransitiveCcNativeLibraries(ruleContext, libraries))) .addNativeDeclaredProvider(instrumentedFilesProvider) .addOutputGroup(OutputGroupInfo.VALIDATION, headerTokens) @@ -1194,7 +1193,7 @@ private static NestedSet collectTransitiveCcNativeLibraries( NestedSetBuilder builder = NestedSetBuilder.linkOrder(); builder.addAll(libraries); for (CcNativeLibraryProvider dep : - ruleContext.getPrerequisites("deps", CcNativeLibraryProvider.class)) { + ruleContext.getPrerequisites("deps", CcNativeLibraryProvider.PROVIDER)) { builder.addTransitive(dep.getTransitiveCcNativeLibraries()); } return builder.build(); 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 0ed8302f3bdce3..905f022cccf59f 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 @@ -479,7 +479,7 @@ public static void init( CcStarlarkApiProvider.maybeAdd(ruleContext, targetBuilder); targetBuilder .setFilesToBuild(filesToBuild) - .addProvider(ccNativeLibraryProvider) + .addNativeDeclaredProvider(ccNativeLibraryProvider) .addNativeDeclaredProvider( CcInfo.builder() .setCcCompilationContext(compilationInfo.getCcCompilationContext()) diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java index 8be360c7a48bb4..c1fea34178e547 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java @@ -1824,6 +1824,12 @@ public CcDebugInfoContext mergeCcDebugInfoFromStarlark( Sequence.cast(debugInfos, CcDebugInfoContext.class, "debug_infos")); } + @Override + public Object getCcNativeLibraryProvider(StarlarkThread thread) throws EvalException { + checkPrivateStarlarkificationAllowlist(thread); + return CcNativeLibraryProvider.PROVIDER; + } + public static void checkPrivateStarlarkificationAllowlist(StarlarkThread thread) throws EvalException { String rulePackage = diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcNativeLibraryProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcNativeLibraryProvider.java index b392cd71de5e61..5e3d1467aee130 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcNativeLibraryProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcNativeLibraryProvider.java @@ -14,10 +14,13 @@ package com.google.devtools.build.lib.rules.cpp; -import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.collect.nestedset.Depset; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.BuiltinProvider; +import com.google.devtools.build.lib.packages.NativeInfo; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; +import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcNativeLibraryProviderApi; /** * A target that provides native libraries in the transitive closure of its deps that are needed for @@ -25,13 +28,24 @@ */ @Immutable @AutoCodec -public final class CcNativeLibraryProvider implements TransitiveInfoProvider { +public final class CcNativeLibraryProvider extends NativeInfo + implements CcNativeLibraryProviderApi { + + public static final BuiltinProvider PROVIDER = + new BuiltinProvider( + "CcNativeLibraryProvider", CcNativeLibraryProvider.class) {}; + private final NestedSet transitiveCcNativeLibraries; public CcNativeLibraryProvider(NestedSet transitiveCcNativeLibraries) { this.transitiveCcNativeLibraries = transitiveCcNativeLibraries; } + @Override + public BuiltinProvider getProvider() { + return PROVIDER; + } + /** * Collects native libraries in the transitive closure of its deps that are needed for executing * C/C++ code. @@ -41,4 +55,9 @@ public CcNativeLibraryProvider(NestedSet transitiveCcNativeLibrar public NestedSet getTransitiveCcNativeLibraries() { return transitiveCcNativeLibraries; } + + @Override + public Depset getTransitiveCcNativeLibrariesStarlark() { + return Depset.of(LibraryToLink.TYPE, getTransitiveCcNativeLibraries()); + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java index 5363279fb62271..b30ef49105cbf7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java @@ -999,7 +999,7 @@ public static CcNativeLibraryProvider collectNativeCcLibraries( NestedSetBuilder result = NestedSetBuilder.linkOrder(); result.addAll(libraries); for (CcNativeLibraryProvider dep : - AnalysisUtils.getProviders(deps, CcNativeLibraryProvider.class)) { + AnalysisUtils.getProviders(deps, CcNativeLibraryProvider.PROVIDER)) { result.addTransitive(dep.getTransitiveCcNativeLibraries()); } return new CcNativeLibraryProvider(result.build()); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/NativeLibraryNestedSetBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/NativeLibraryNestedSetBuilder.java index f994e13d68fa0a..e9fe6e9ec6d62d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/NativeLibraryNestedSetBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/NativeLibraryNestedSetBuilder.java @@ -58,7 +58,7 @@ public NativeLibraryNestedSetBuilder addJavaTarget(TransitiveInfoCollection dep) return this; } - CcNativeLibraryProvider ccProvider = dep.getProvider(CcNativeLibraryProvider.class); + CcNativeLibraryProvider ccProvider = dep.get(CcNativeLibraryProvider.PROVIDER); if (ccProvider != null) { builder.addTransitive(ccProvider.getTransitiveCcNativeLibraries()); return this; @@ -80,7 +80,7 @@ public NativeLibraryNestedSetBuilder addCcTargets( /** Include native Java libraries of a specified target into the nested set. */ private void addCcTarget(TransitiveInfoCollection dep) { - CcNativeLibraryProvider provider = dep.getProvider(CcNativeLibraryProvider.class); + CcNativeLibraryProvider provider = dep.get(CcNativeLibraryProvider.PROVIDER); if (provider != null) { builder.addTransitive(provider.getTransitiveCcNativeLibraries()); } else { diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java index 957e0c2b1821bf..1321d6443a155a 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java @@ -1255,4 +1255,10 @@ LtoBackendArtifactsT createLtoBackendArtifacts( Sequence argv, StarlarkThread thread) throws EvalException; + + @StarlarkMethod( + name = "get_CcNativeLibraryProvider", + documented = false, + useStarlarkThread = true) + Object getCcNativeLibraryProvider(StarlarkThread thread) throws EvalException; } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcNativeLibraryProviderApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcNativeLibraryProviderApi.java new file mode 100644 index 00000000000000..ddedb3fc118cee --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcNativeLibraryProviderApi.java @@ -0,0 +1,33 @@ +// 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.cpp; + +import com.google.devtools.build.docgen.annot.DocCategory; +import com.google.devtools.build.lib.collect.nestedset.Depset; +import com.google.devtools.build.lib.starlarkbuildapi.core.StructApi; +import net.starlark.java.annot.StarlarkBuiltin; +import net.starlark.java.annot.StarlarkMethod; +import net.starlark.java.eval.EvalException; + +/** + * Provider for native libraries in the transitive closure of a target that are needed for executing + * C++ code. + */ +@StarlarkBuiltin(name = "CcNativeLibrary", documented = false, category = DocCategory.PROVIDER) +public interface CcNativeLibraryProviderApi extends StructApi { + + @StarlarkMethod(name = "libs", structField = true, documented = false) + Depset getTransitiveCcNativeLibrariesStarlark() throws EvalException; +} diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java index 3ed9b39b48e82a..3bc0df8eb29bba 100644 --- a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java +++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcLinkingContextApi; import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcLinkingOutputsApi; import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcModuleApi; +import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcNativeLibraryProviderApi; import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcToolchainConfigInfoApi; import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcToolchainProviderApi; import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcToolchainVariablesApi; @@ -406,4 +407,10 @@ public LtoBackendArtifactsApi createLtoBackendArtifacts( throws EvalException { return null; } + + @Override + public CcNativeLibraryProviderApi getCcNativeLibraryProvider(StarlarkThread thread) + throws EvalException { + return null; + } } 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 6dcda103e888c1..b2fd1bac43a198 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 @@ -222,7 +222,7 @@ public void testFilesToBuild() throws Exception { .containsExactly(archive, implSharedObject, implInterfaceSharedObject); assertThat( LibraryToLink.getDynamicLibrariesForLinking( - hello.getProvider(CcNativeLibraryProvider.class).getTransitiveCcNativeLibraries())) + hello.get(CcNativeLibraryProvider.PROVIDER).getTransitiveCcNativeLibraries())) .containsExactly(implInterfaceSharedObjectLink); assertThat( hello @@ -265,7 +265,7 @@ public void testFilesToBuildWithInterfaceSharedObjects() throws Exception { .containsExactly(archive, sharedObject, implSharedObject); assertThat( LibraryToLink.getDynamicLibrariesForLinking( - hello.getProvider(CcNativeLibraryProvider.class).getTransitiveCcNativeLibraries())) + hello.get(CcNativeLibraryProvider.PROVIDER).getTransitiveCcNativeLibraries())) .containsExactly(sharedObjectLink); assertThat( hello diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcCommonTest.java index 1e39cb00b288ef..8d8aa829ffff8f 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcCommonTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/StarlarkCcCommonTest.java @@ -27,6 +27,7 @@ import com.google.devtools.build.lib.actions.CommandLineExpansionException; import com.google.devtools.build.lib.actions.util.ActionsTestUtil; import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.DefaultInfo; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.util.AnalysisMock; import com.google.devtools.build.lib.analysis.util.AnalysisTestUtil; @@ -7211,6 +7212,64 @@ public void testExtraLinkTimeLibraryApiRaisesError() throws Exception { } } + @Test + public void testDisallowedCcNativeLibraryRaisesError() throws Exception { + scratch.file( + "b/BUILD", "load('//b:rule.bzl', 'test_rule')", "test_rule(", " name = 'test',", ")"); + scratch.file( + "b/rule.bzl", + "def _impl(ctx):", + " cc_common.get_CcNativeLibraryProvider()", + " return DefaultInfo()", + "test_rule = rule(implementation = _impl)"); + + AssertionError e = assertThrows(AssertionError.class, () -> getConfiguredTarget("//b:test")); + assertThat(e).hasMessageThat().contains("Rule in 'b' cannot use private API"); + } + + @Test + public void testAllowedCcNativeLibraryProviderIsUsable() throws Exception { + scratch.file( + "b/BUILD", + "load('//bazel_internal/test_rules/cc:rule.bzl', 'test_rule')", + "test_rule(", + " name = 'test',", + " cc_dep = ':foo',", + ")", + "cc_library(", + " name = 'foo',", + " srcs = ['foo.cc'],", + ")"); + scratch.file("bazel_internal/test_rules/cc/BUILD"); + scratch.file( + "bazel_internal/test_rules/cc/rule.bzl", + "def _impl(ctx):", + " CcNativeLibraryProvider = cc_common.get_CcNativeLibraryProvider()", + " libs = ctx.attr.cc_dep[CcNativeLibraryProvider].libs", + " files = []", + " for l in libs.to_list():", + " files.append(l.dynamic_library)", + " files.append(l.interface_library)", + " files.append(l.static_library)", + " files.append(l.pic_static_library)", + " files = [f for f in files if f != None]", + " runfiles = ctx.runfiles(files=files)", + " return [DefaultInfo(runfiles=runfiles)]", + "test_rule = rule(", + " implementation = _impl,", + " attrs = {", + " 'cc_dep': attr.label(),", + " },", + ")"); + + ConfiguredTarget test = getConfiguredTarget("//b:test"); + + assertThat( + test.get(DefaultInfo.PROVIDER).getDefaultRunfiles().getAllArtifacts().toList().stream() + .map(Artifact::getFilename)) + .containsExactly("libfoo.a"); + } + @Test public void testAllowedVariableExtensionCompileApi() throws Exception { runTestVariableExtension(/* call= */ "compile", /* allowed= */ true);