diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
index f4efdad6a6d0d8..eb8c6a9a568103 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
@@ -22,9 +22,11 @@
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCcTestRule;
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses;
import com.google.devtools.build.lib.rules.core.CoreRules;
+import com.google.devtools.build.lib.rules.cpp.CcCompilationInfo;
import com.google.devtools.build.lib.rules.cpp.CcHostToolchainAliasRule;
import com.google.devtools.build.lib.rules.cpp.CcImportRule;
import com.google.devtools.build.lib.rules.cpp.CcLibcTopAlias;
+import com.google.devtools.build.lib.rules.cpp.CcLinkingInfo;
import com.google.devtools.build.lib.rules.cpp.CcModule;
import com.google.devtools.build.lib.rules.cpp.CcToolchainAliasRule;
import com.google.devtools.build.lib.rules.cpp.CcToolchainRule;
@@ -76,6 +78,8 @@ public void init(ConfiguredRuleClassProvider.Builder builder) {
builder.addRuleDefinition(new FdoPrefetchHintsRule());
builder.addSkylarkBootstrap(new CcBootstrap(new CcModule()));
+ builder.addSkylarkAccessibleTopLevels("CcCompilationInfo", CcCompilationInfo.PROVIDER);
+ builder.addSkylarkAccessibleTopLevels("CcLinkingInfo", CcLinkingInfo.PROVIDER);
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
index a026a0a1b35a78..6a7219c68f777a 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
@@ -52,7 +52,9 @@
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.packages.TriState;
+import com.google.devtools.build.lib.rules.cpp.CcModule.CcSkylarkInfo;
import com.google.devtools.build.lib.rules.cpp.CcToolchain;
import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
@@ -349,7 +351,9 @@ public Object getDefault(AttributeMap rule) {
attr("deps", LABEL_LIST)
.allowedRuleClasses(DEPS_ALLOWED_RULES)
.allowedFileTypes(CppFileTypes.LINKER_SCRIPT)
- .skipAnalysisTimeFileTypeCheck())
+ .skipAnalysisTimeFileTypeCheck()
+ .mandatoryProviders(
+ SkylarkProviderIdentifier.forKey(CcSkylarkInfo.PROVIDER.getKey())))
/*
The Windows DEF file to be passed to linker.
This attribute should only be used when Windows is the target platform.
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 0e7eca0a516365..baaf365864baa1 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
@@ -17,13 +17,24 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
+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;
import com.google.devtools.build.lib.packages.Provider;
+import com.google.devtools.build.lib.rules.cpp.CcModule.CcSkylarkInfo;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
+import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcModuleApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcSkylarkInfoApi;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.SkylarkDict;
@@ -33,7 +44,32 @@
/** A module that contains Skylark utilities for C++ support. */
public class CcModule
- implements CcModuleApi {
+ implements CcModuleApi<
+ CcToolchainProvider,
+ FeatureConfiguration,
+ CcToolchainVariables,
+ LibraryToLink,
+ CcLinkParams,
+ CcSkylarkInfo> {
+
+ /**
+ * C++ Skylark rules should have this provider so that native rules can depend on them. This will
+ * eventually go away once b/73921130 is fixed.
+ */
+ @Immutable
+ @AutoCodec
+ public static final class CcSkylarkInfo extends NativeInfo implements CcSkylarkInfoApi {
+ public static final ObjectCodec CODEC = new CcModule_CcSkylarkInfo_AutoCodec();
+
+ public static final NativeProvider PROVIDER =
+ new NativeProvider(CcSkylarkInfo.class, "CcSkylarkInfo") {};
+
+ @AutoCodec.Instantiator
+ @VisibleForSerialization
+ CcSkylarkInfo() {
+ super(PROVIDER);
+ }
+ }
@Override
public Provider getCcToolchainProvider() {
@@ -182,7 +218,7 @@ protected static T convertFromNoneable(Object obj, @Nullable T defaultValue)
}
/** Converts an object that can be the either SkylarkNestedSet or None into NestedSet. */
- protected NestedSet asStringNestedSet(Object o) throws EvalException {
+ protected NestedSet asStringNestedSet(Object o) {
SkylarkNestedSet skylarkNestedSet = convertFromNoneable(o, /* defaultValue= */ null);
if (skylarkNestedSet != null) {
return skylarkNestedSet.getSet(String.class);
@@ -190,4 +226,71 @@ protected NestedSet asStringNestedSet(Object o) throws EvalException {
return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
}
}
+
+ @Override
+ public LibraryToLink createLibraryLinkerInput(
+ SkylarkRuleContext skylarkRuleContext, Artifact library, String skylarkArtifactCategory)
+ throws EvalException {
+ CcCommon.checkRuleWhitelisted(skylarkRuleContext);
+ ArtifactCategory artifactCategory =
+ ArtifactCategory.fromString(
+ skylarkArtifactCategory,
+ skylarkRuleContext.getRuleContext().getRule().getLocation(),
+ "artifact_category");
+ return LinkerInputs.opaqueLibraryToLink(
+ library, artifactCategory, CcLinkingOutputs.libraryIdentifierOf(library));
+ }
+
+ @Override
+ public LibraryToLink createSymlinkLibraryLinkerInput(
+ SkylarkRuleContext skylarkRuleContext, CcToolchainProvider ccToolchain, Artifact library) {
+ Artifact dynamicLibrarySymlink =
+ SolibSymlinkAction.getDynamicLibrarySymlink(
+ skylarkRuleContext.getRuleContext(),
+ ccToolchain.getSolibDirectory(),
+ library,
+ /* preserveName= */ true,
+ /* prefixConsumer= */ true,
+ skylarkRuleContext.getRuleContext().getConfiguration());
+ return LinkerInputs.solibLibraryToLink(
+ dynamicLibrarySymlink, library, CcLinkingOutputs.libraryIdentifierOf(library));
+ }
+
+ @Override
+ public CcLinkParams createCcLinkParams(
+ SkylarkRuleContext skylarkRuleContext,
+ Object skylarkLibrariesToLink,
+ Object skylarkDynamicLibrariesForRuntime,
+ Object skylarkUserLinkFlags)
+ throws EvalException {
+ CcCommon.checkRuleWhitelisted(skylarkRuleContext);
+
+ SkylarkNestedSet librariesToLink = convertFromNoneable(skylarkLibrariesToLink, null);
+ SkylarkNestedSet dynamicLibrariesForRuntime =
+ convertFromNoneable(skylarkDynamicLibrariesForRuntime, null);
+ SkylarkNestedSet userLinkFlags = convertFromNoneable(skylarkUserLinkFlags, null);
+
+ CcLinkParams.Builder builder = CcLinkParams.builder();
+ if (librariesToLink != null) {
+ builder.addLibraries(librariesToLink.toCollection(LibraryToLink.class));
+ }
+ if (dynamicLibrariesForRuntime != null) {
+ builder.addDynamicLibrariesForRuntime(
+ dynamicLibrariesForRuntime.toCollection(Artifact.class));
+ }
+ if (userLinkFlags != null) {
+ builder.addLinkOpts(userLinkFlags.toCollection(String.class));
+ }
+ return builder.build();
+ }
+
+ @Override
+ public CcSkylarkInfo createCcSkylarkInfo(Object skylarkRuleContextObject) throws EvalException {
+ SkylarkRuleContext skylarkRuleContext =
+ convertFromNoneable(skylarkRuleContextObject, /* defaultValue= */ null);
+ if (skylarkRuleContext != null) {
+ CcCommon.checkRuleWhitelisted(skylarkRuleContext);
+ }
+ return new CcSkylarkInfo();
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInput.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInput.java
index 9cbcf6743445a6..c2da5135bf30d8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInput.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInput.java
@@ -15,23 +15,19 @@
package com.google.devtools.build.lib.rules.cpp;
import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.LinkerInputApi;
/**
* Something that appears on the command line of the linker. Since we sometimes expand archive files
* to their constituent object files, we need to keep information whether a certain file contains
* embedded objects and if so, the list of the object files themselves.
*/
-public interface LinkerInput {
+public interface LinkerInput extends LinkerInputApi {
/**
* Returns the type of the linker input.
*/
ArtifactCategory getArtifactCategory();
- /** Returns the artifact that is the input of the linker. */
- @SkylarkCallable(name = "artifact", doc = "Artifact passed to the linker.")
- Artifact getArtifact();
-
/**
* Returns the original library to link. If this library is a solib symlink, returns the
* artifact the symlink points to, otherwise, the library itself.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java
index 599710579235cc..5ccef60859f60e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java
@@ -22,8 +22,7 @@
import com.google.devtools.build.lib.concurrent.ThreadSafety;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
-import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.LibraryToLinkApi;
/**
* Factory for creating new {@link LinkerInput} objects.
@@ -154,12 +153,7 @@ public boolean isFake() {
* A library the user can link to. This is different from a simple linker input in that it also
* has a library identifier.
*/
- @SkylarkModule(
- name = "LibraryToLink",
- category = SkylarkModuleCategory.BUILTIN,
- documented = false,
- doc = "A library the user can link to.")
- public interface LibraryToLink extends LinkerInput {
+ public interface LibraryToLink extends LinkerInput, LibraryToLinkApi {
ImmutableMap getLtoBitcodeFiles();
/**
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcModuleApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcModuleApi.java
index 73c5e498a837ac..f1e3a65c85103c 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcModuleApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcModuleApi.java
@@ -14,8 +14,10 @@
package com.google.devtools.build.lib.skylarkbuildapi.cpp;
-
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
import com.google.devtools.build.lib.skylarkbuildapi.ProviderApi;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkRuleContextApi;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.ParamType;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
@@ -33,7 +35,10 @@
public interface CcModuleApi<
CcToolchainProviderT extends CcToolchainProviderApi,
FeatureConfigurationT extends FeatureConfigurationApi,
- CcToolchainVariablesT extends CcToolchainVariablesApi> {
+ CcToolchainVariablesT extends CcToolchainVariablesApi,
+ LibraryToLinkT extends LibraryToLinkApi,
+ CcLinkParamsT extends CcLinkParamsApi,
+ CcSkylarkInfoT extends CcSkylarkInfoApi> {
@SkylarkCallable(
name = "CcToolchainInfo",
@@ -450,4 +455,135 @@ CcToolchainVariablesT getLinkBuildVariables(
@SkylarkCallable(name = "empty_variables", documented = false)
CcToolchainVariablesT getVariables();
+
+ @SkylarkCallable(
+ name = "create_library_to_link",
+ documented = false,
+ parameters = {
+ @Param(
+ name = "ctx",
+ doc = "Skylark rule context.",
+ positional = false,
+ named = true,
+ type = SkylarkRuleContext.class),
+ @Param(
+ name = "library",
+ doc = "Library to be linked.",
+ positional = false,
+ named = true,
+ type = Artifact.class),
+ @Param(
+ name = "artifact_category",
+ doc =
+ "Artifact category. Can be: static_library, alwayslink_static_library, "
+ + "dynamic_library or interface_library",
+ positional = false,
+ named = true,
+ type = String.class)
+ })
+ LibraryToLinkT createLibraryLinkerInput(
+ SkylarkRuleContext skylarkRuleContext, Artifact library, String skylarkArtifactCategory)
+ throws EvalException;
+
+ @SkylarkCallable(
+ name = "create_symlink_library_to_link",
+ documented = false,
+ parameters = {
+ @Param(
+ name = "ctx",
+ doc = "Skylark rule context.",
+ positional = false,
+ named = true,
+ type = SkylarkRuleContext.class),
+ @Param(
+ name = "cc_toolchain",
+ doc = "C++ toolchain provider to be used.",
+ positional = false,
+ named = true,
+ type = CcToolchainProviderApi.class),
+ @Param(
+ name = "library",
+ doc = "Library that should be symlinked.",
+ positional = false,
+ named = true,
+ type = Artifact.class),
+ })
+ LibraryToLinkT createSymlinkLibraryLinkerInput(
+ SkylarkRuleContext skylarkRuleContext, CcToolchainProviderT ccToolchain, Artifact library);
+
+ @SkylarkCallable(
+ name = "create_cc_link_params",
+ doc = "Creates cc link parameters",
+ parameters = {
+ @Param(
+ name = "ctx",
+ positional = false,
+ named = true,
+ type = SkylarkRuleContextApi.class,
+ doc = "The rule context."),
+ @Param(
+ name = "libraries_to_link",
+ doc =
+ "List of libraries that should be passed to the linker/archiver. They can be "
+ + "static and/or dynamic libraries.",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "None",
+ allowedTypes = {
+ @ParamType(type = SkylarkNestedSet.class),
+ @ParamType(type = NoneType.class)
+ }),
+ @Param(
+ name = "dynamic_libraries_for_runtime",
+ doc =
+ "When 'libraries_to_link' has dynamic libraries, then the runtime library can "
+ + "be specified as well. This is not obligatory though, as we may provide a "
+ + "library for linking and at runtime the actual library will be provided by "
+ + "the system.",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "None",
+ allowedTypes = {
+ @ParamType(type = SkylarkNestedSet.class),
+ @ParamType(type = NoneType.class)
+ }),
+ @Param(
+ name = "user_link_flags",
+ doc = "List of user provided linker flags.",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "None",
+ allowedTypes = {
+ @ParamType(type = SkylarkNestedSet.class),
+ @ParamType(type = NoneType.class)
+ })
+ })
+ CcLinkParamsT createCcLinkParams(
+ SkylarkRuleContext skylarkRuleContext,
+ Object skylarkLibrariesToLink,
+ Object skylarkDynamicLibrariesForRuntime,
+ Object skylarkUserLinkFlags)
+ throws EvalException;
+
+ @SkylarkCallable(
+ name = "create_cc_skylark_info",
+ documented = false,
+ parameters = {
+ // TODO(plf): Make this parameter mandatory. Change cc_embed_data.bzl first.
+ @Param(
+ name = "ctx",
+ doc = "Skylark rule context.",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "None",
+ allowedTypes = {
+ @ParamType(type = SkylarkRuleContextApi.class),
+ @ParamType(type = NoneType.class)
+ })
+ })
+ CcSkylarkInfoT createCcSkylarkInfo(Object skylarkRuleContextObject) throws EvalException;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcSkylarkInfoApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcSkylarkInfoApi.java
new file mode 100644
index 00000000000000..dc764a064fe931
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcSkylarkInfoApi.java
@@ -0,0 +1,26 @@
+// Copyright 2018 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.skylarkbuildapi.cpp;
+
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+
+/** Skylark rules need to provide this to be a dependency of native cc_* rules. */
+@SkylarkModule(
+ name = "cc_skylark_info",
+ category = SkylarkModuleCategory.PROVIDER,
+ doc = "Temporary provider to mark C++ Skylark rules")
+// TODO(b/77669139): Delete this class. Use {@link CcCompilationInfo} instead.
+public interface CcSkylarkInfoApi {}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LibraryToLinkApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LibraryToLinkApi.java
new file mode 100644
index 00000000000000..a8421654c76a24
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LibraryToLinkApi.java
@@ -0,0 +1,29 @@
+// Copyright 2018 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.skylarkbuildapi.cpp;
+
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+
+/**
+ * A library the user can link to. This is different from a simple linker input in that it also has
+ * a library identifier.
+ */
+@SkylarkModule(
+ name = "LibraryToLink",
+ category = SkylarkModuleCategory.BUILTIN,
+ documented = false,
+ doc = "A library the user can link to.")
+public interface LibraryToLinkApi {}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LinkerInputApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LinkerInputApi.java
new file mode 100644
index 00000000000000..13707d21e6232a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LinkerInputApi.java
@@ -0,0 +1,29 @@
+// 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.skylarkbuildapi.cpp;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+
+/**
+ * Something that appears on the command line of the linker. Since we sometimes expand archive files
+ * to their constituent object files, we need to keep information whether a certain file contains
+ * embedded objects and if so, the list of the object files themselves.
+ */
+public interface LinkerInputApi {
+ /** Returns the artifact that is the input of the linker. */
+ @SkylarkCallable(name = "artifact", doc = "Artifact passed to the linker.")
+ Artifact getArtifact();
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/BUILD b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/BUILD
index a8fc8a287ce34e..defdfe7fe70460 100644
--- a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/BUILD
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/BUILD
@@ -13,8 +13,10 @@ java_library(
name = "cpp",
srcs = glob(["*.java"]),
deps = [
+ "//src/main/java/com/google/devtools/build/lib:build-base",
"//src/main/java/com/google/devtools/build/lib:skylarkinterface",
"//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/skylarkbuildapi",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp",
"//src/main/java/com/google/devtools/build/skydoc/fakebuildapi",
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 c8f7a067789d63..6e3ab8377ac5e5 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
@@ -14,21 +14,30 @@
package com.google.devtools.build.skydoc.fakebuildapi.cpp;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
import com.google.devtools.build.lib.skylarkbuildapi.ProviderApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcLinkParamsApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcModuleApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcSkylarkInfoApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcToolchainProviderApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcToolchainVariablesApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.FeatureConfigurationApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.LibraryToLinkApi;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.skydoc.fakebuildapi.FakeProviderApi;
-/**
- * Fake implementation of {@link CcModuleApi}.
- */
-public class FakeCcModule implements CcModuleApi {
+/** Fake implementation of {@link CcModuleApi}. */
+public class FakeCcModule
+ implements CcModuleApi<
+ CcToolchainProviderApi,
+ FeatureConfigurationApi,
+ CcToolchainVariablesApi,
+ LibraryToLinkApi,
+ CcLinkParamsApi,
+ CcSkylarkInfoApi> {
@Override
public ProviderApi getCcToolchainProvider() {
@@ -88,4 +97,33 @@ public CcToolchainVariablesApi getLinkBuildVariables(CcToolchainProviderApi ccTo
public CcToolchainVariablesApi getVariables() {
return null;
}
+
+ @Override
+ public LibraryToLinkApi createLibraryLinkerInput(
+ SkylarkRuleContext skylarkRuleContext, Artifact library, String skylarkArtifactCategory)
+ throws EvalException {
+ return null;
+ }
+
+ @Override
+ public LibraryToLinkApi createSymlinkLibraryLinkerInput(
+ SkylarkRuleContext skylarkRuleContext, CcToolchainProviderApi ccToolchain, Artifact library) {
+ return null;
+ }
+
+ @Override
+ public CcLinkParamsApi createCcLinkParams(
+ SkylarkRuleContext skylarkRuleContext,
+ Object skylarkLibrariesToLink,
+ Object skylarkDynamicLibrariesForRuntime,
+ Object skylarkUserLinkFlags)
+ throws EvalException {
+ return null;
+ }
+
+ @Override
+ public CcSkylarkInfoApi createCcSkylarkInfo(Object skylarkRuleContextObject)
+ throws EvalException {
+ return null;
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
index 5f4fa9c5729f99..3d4a6d5cd0965b 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
@@ -14,9 +14,12 @@
package com.google.devtools.build.lib.rules.cpp;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
@@ -24,9 +27,11 @@
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.packages.util.ResourceLoader;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.testutil.TestConstants;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -36,6 +41,12 @@
*/
@RunWith(JUnit4.class)
public class SkylarkCcCommonTest extends BuildViewTestCase {
+
+ @Before
+ public void setConfiguration() throws Exception {
+ useConfiguration("--experimental_enable_cc_skylark_api");
+ }
+
@Test
public void testGetToolForAction() throws Exception {
scratch.file(
@@ -121,7 +132,7 @@ public void testFeatureConfigurationWithAdditionalUnsupportedFeature() throws Ex
AnalysisMock.get()
.ccSupport()
.setupCrosstool(mockToolsConfig, "feature { name: 'foo_feature' }");
- useConfiguration("--features=foo_feature");
+ useConfiguration("--features=foo_feature", "--experimental_enable_cc_skylark_api");
scratch.file(
"a/BUILD",
"load(':rule.bzl', 'crule')",
@@ -663,7 +674,7 @@ public void testMustKeepDebugLinkVariables() throws Exception {
@Test
public void testIsLinkingDynamicLibraryLinkVariables() throws Exception {
- useConfiguration("--linkopt=-pie");
+ useConfiguration("--linkopt=-pie", "--experimental_enable_cc_skylark_api");
assertThat(
commandLineForVariables(
CppActionNames.CPP_LINK_EXECUTABLE,
@@ -688,7 +699,9 @@ public void testIsLinkingDynamicLibraryLinkVariables() throws Exception {
@Test
public void testIsUsingLinkerLinkVariables() throws Exception {
- useConfiguration("--linkopt=-i_dont_want_to_see_this_on_archiver_command_line");
+ useConfiguration(
+ "--linkopt=-i_dont_want_to_see_this_on_archiver_command_line",
+ "--experimental_enable_cc_skylark_api");
assertThat(
commandLineForVariables(
CppActionNames.CPP_LINK_EXECUTABLE,
@@ -821,4 +834,206 @@ private SkylarkList commandLineForVariables(
SkylarkList result = (SkylarkList) r.get("command_line");
return result;
}
+
+ @Test
+ public void testCcCompilationProvider() throws Exception {
+ scratch.file(
+ "a/BUILD",
+ "load('//tools/build_defs/cc:rule.bzl', 'crule')",
+ "cc_library(",
+ " name='lib',",
+ " hdrs = ['lib.h'],",
+ " srcs = ['lib.cc'],",
+ " deps = ['r']",
+ ")",
+ "crule(name='r')");
+ scratch.file("tools/build_defs/cc/BUILD", "");
+ scratch.file(
+ "tools/build_defs/cc/rule.bzl",
+ "def _impl(ctx):",
+ " cc_compilation_info = CcCompilationInfo(headers=depset([ctx.file._header]))",
+ " return [",
+ " cc_compilation_info, cc_common.create_cc_skylark_info(ctx=ctx),",
+ " ]",
+ "crule = rule(",
+ " _impl,",
+ " attrs = { ",
+ " '_header': attr.label(allow_single_file=True, default=Label('//a:header.h'))",
+ " },",
+ " fragments = ['cpp'],",
+ ");");
+
+ ConfiguredTarget r = getConfiguredTarget("//a:lib");
+ @SuppressWarnings("unchecked")
+ CcCompilationContext ccCompilationContext =
+ r.get(CcCompilationInfo.PROVIDER).getCcCompilationContext();
+ assertThat(
+ ccCompilationContext
+ .getDeclaredIncludeSrcs()
+ .toCollection()
+ .stream()
+ .map(Artifact::getFilename)
+ .collect(ImmutableList.toImmutableList()))
+ .containsExactly("lib.h", "header.h");
+ }
+
+ @Test
+ public void testLibraryLinkerInputs() throws Exception {
+ scratch.file("a/BUILD", "load('//tools/build_defs/cc:rule.bzl', 'crule')", "crule(name='r')");
+ scratch.file("a/lib.a", "");
+ scratch.file("a/lib.lo", "");
+ scratch.file("a/lib.so", "");
+ scratch.file("a/lib.ifso", "");
+ scratch.file("tools/build_defs/cc/BUILD", "");
+ scratch.file(
+ "tools/build_defs/cc/rule.bzl",
+ "def _create(ctx, lib, c):",
+ " return cc_common.create_library_to_link(ctx=ctx, library=lib, artifact_category=c)",
+ "def _impl(ctx):",
+ " static_library = _create(ctx, ctx.file.liba, 'static_library')",
+ " alwayslink_static_library = _create(ctx, ctx.file.liblo, 'alwayslink_static_library')",
+ " dynamic_library = _create(ctx, ctx.file.libso, 'dynamic_library')",
+ " interface_library = _create(ctx, ctx.file.libifso, 'interface_library')",
+ " toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]",
+ " symlink_library = cc_common.create_symlink_library_to_link(",
+ " ctx=ctx, cc_toolchain=toolchain, library=ctx.file.libso)",
+ " return struct(",
+ " static_library = static_library,",
+ " alwayslink_static_library = alwayslink_static_library,",
+ " dynamic_library = dynamic_library,",
+ " interface_library = interface_library,",
+ " symlink_library = symlink_library",
+ " )",
+ "crule = rule(",
+ " _impl,",
+ " attrs = { ",
+ " 'liba': attr.label(default='//a:lib.a', allow_single_file=True),",
+ " 'liblo': attr.label(default='//a:lib.lo', allow_single_file=True),",
+ " 'libso': attr.label(default='//a:lib.so', allow_single_file=True),",
+ " 'libifso': attr.label(default='//a:lib.ifso', allow_single_file=True),",
+ " '_cc_toolchain': attr.label(default =",
+ " configuration_field(fragment = 'cpp', name = 'cc_toolchain'))",
+ " },",
+ " fragments = ['cpp'],",
+ ");");
+ ConfiguredTarget r = getConfiguredTarget("//a:r");
+ @SuppressWarnings("unchecked")
+ LibraryToLink staticLibrary = (LibraryToLink) r.get("static_library");
+ assertThat(staticLibrary.getArtifact().getFilename()).isEqualTo("lib.a");
+ LibraryToLink alwaysLinkStaticLibrary = (LibraryToLink) r.get("alwayslink_static_library");
+ assertThat(alwaysLinkStaticLibrary.getArtifact().getFilename()).isEqualTo("lib.lo");
+ LibraryToLink dynamicLibrary = (LibraryToLink) r.get("dynamic_library");
+ assertThat(dynamicLibrary.getArtifact().getFilename()).isEqualTo("lib.so");
+ LibraryToLink interfaceLibrary = (LibraryToLink) r.get("interface_library");
+ assertThat(interfaceLibrary.getArtifact().getFilename()).isEqualTo("lib.ifso");
+ LibraryToLink symlinkLibrary = (LibraryToLink) r.get("symlink_library");
+ assertThat(symlinkLibrary.getArtifact().getFilename()).isEqualTo("lib.so");
+ assertThat(symlinkLibrary.getArtifact().getPath())
+ .isNotEqualTo(symlinkLibrary.getOriginalLibraryArtifact().getPath());
+ }
+
+ @Test
+ public void testLibraryLinkerInputArtifactCategoryError() throws Exception {
+ scratch.file("a/BUILD", "load('//tools/build_defs/cc:rule.bzl', 'crule')", "crule(name='r')");
+ scratch.file("a/lib.a", "");
+ scratch.file("tools/build_defs/cc/BUILD", "");
+ scratch.file(
+ "tools/build_defs/cc/rule.bzl",
+ "def _impl(ctx):",
+ " executable = cc_common.create_library_to_link(",
+ " ctx=ctx, library=ctx.file.lib, artifact_category='executable')",
+ " return struct(",
+ " executable = executable,",
+ " )",
+ "crule = rule(",
+ " _impl,",
+ " attrs = { ",
+ " 'lib': attr.label(default='//a:lib.a', allow_single_file=True),",
+ " },",
+ " fragments = ['cpp'],",
+ ");");
+ AssertionError e = assertThrows(AssertionError.class, () -> getConfiguredTarget("//a:r"));
+ assertThat(e)
+ .hasMessageThat()
+ .contains(
+ "Possible values for artifact_category: static_library, alwayslink_static_library, "
+ + "dynamic_library, interface_library");
+ }
+
+ @Test
+ public void testCcLinkingProviderParamsWithoutFlag() throws Exception {
+ useConfiguration("--noexperimental_enable_cc_skylark_api");
+ setUpCcLinkingProviderParamsTest();
+ AssertionError e = assertThrows(AssertionError.class, () -> getConfiguredTarget("//a:r"));
+ assertThat(e)
+ .hasMessageThat()
+ .contains(
+ "Pass --experimental_enable_cc_skylark_api in order to "
+ + "use the C++ API. Beware that we will be making breaking changes to this API "
+ + "without prior warning.");
+ }
+
+ @Test
+ public void testCcLinkingProviderParamsWithFlag() throws Exception {
+ setUpCcLinkingProviderParamsTest();
+ ConfiguredTarget r = getConfiguredTarget("//a:r");
+ @SuppressWarnings("unchecked")
+ CcLinkParamsStore ccLinkParamsStore =
+ ((CcLinkingInfo) r.get("cc_linking_info")).getCcLinkParamsStore();
+ assertThat(ccLinkParamsStore).isNotNull();
+ assertThat(
+ ccLinkParamsStore
+ .get(/* linkingStatically= */ true, /* linkShared= */ true)
+ .flattenedLinkopts())
+ .containsExactly("-static_shared");
+ assertThat(
+ ccLinkParamsStore
+ .get(/* linkingStatically= */ true, /* linkShared= */ false)
+ .flattenedLinkopts())
+ .containsExactly("-static_no_shared");
+ assertThat(
+ ccLinkParamsStore
+ .get(/* linkingStatically= */ false, /* linkShared= */ true)
+ .flattenedLinkopts())
+ .containsExactly("-no_static_shared");
+ assertThat(
+ ccLinkParamsStore
+ .get(/* linkingStatically= */ false, /* linkShared= */ false)
+ .flattenedLinkopts())
+ .containsExactly("-no_static_no_shared");
+ }
+
+ private void setUpCcLinkingProviderParamsTest() throws Exception {
+ scratch.file("a/BUILD", "load('//tools/build_defs/cc:rule.bzl', 'crule')", "crule(name='r')");
+ scratch.file("a/lib.a", "");
+ scratch.file("a/lib.so", "");
+ scratch.file("tools/build_defs/cc/BUILD", "");
+ scratch.file(
+ "tools/build_defs/cc/rule.bzl",
+ "def _create(ctx, l, r, f):",
+ " return cc_common.create_cc_link_params(",
+ " ctx=ctx, libraries_to_link=depset(l), dynamic_libraries_for_runtime=depset(r),",
+ " user_link_flags=depset(f))",
+ "def _impl(ctx):",
+ " liba = cc_common.create_library_to_link(ctx=ctx, library=ctx.file.liba,",
+ " artifact_category='static_library')",
+ " ss = _create(ctx, [liba], [ctx.file.libso], ['-static_shared'])",
+ " sns = _create(ctx, [liba], [ctx.file.libso], ['-static_no_shared'])",
+ " nss = _create(ctx, [liba], [ctx.file.libso], ['-no_static_shared'])",
+ " nsns = _create(ctx, [liba], [ctx.file.libso], ['-no_static_no_shared'])",
+ " cc_linking_info = CcLinkingInfo(",
+ " static_shared_params=ss, static_no_shared_params=sns,",
+ " no_static_shared_params=nss, no_static_no_shared_params=nsns)",
+ " return struct(",
+ " cc_linking_info = cc_linking_info,",
+ " )",
+ "crule = rule(",
+ " _impl,",
+ " attrs = { ",
+ " 'liba': attr.label(default='//a:lib.a', allow_single_file=True),",
+ " 'libso': attr.label(default='//a:lib.so', allow_single_file=True),",
+ " },",
+ " fragments = ['cpp'],",
+ ");");
+ }
}