C++: Expose several methods from C++ to Starlark
The CcCommon object itself (unrelated to cc_common) can only be created from
builtins. Eventually all the code in CcCommon should be starlarkified and be
made part of cc_helper.
RELNOTES:none
PiperOrigin-RevId: 397070425
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
index f48a3b6..5a09880 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
@@ -13,6 +13,7 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.cpp;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
@@ -72,13 +73,17 @@
import java.util.regex.PatternSyntaxException;
import java.util.stream.Stream;
import javax.annotation.Nullable;
+import net.starlark.java.annot.Param;
+import net.starlark.java.annot.StarlarkMethod;
import net.starlark.java.eval.EvalException;
+import net.starlark.java.eval.Sequence;
import net.starlark.java.eval.Starlark;
+import net.starlark.java.eval.StarlarkList;
+import net.starlark.java.eval.StarlarkValue;
+import net.starlark.java.eval.Tuple;
-/**
- * Common parts of the implementation of cc rules.
- */
-public final class CcCommon {
+/** Common parts of the implementation of cc rules. */
+public final class CcCommon implements StarlarkValue {
/** Name of the build variable for the sysroot path variable name. */
public static final String SYSROOT_VARIABLE_NAME = "sysroot";
@@ -201,9 +206,14 @@
return mergedOutputGroups;
}
+ @StarlarkMethod(name = "linkopts", structField = true, documented = false)
+ public Sequence<String> getLinkoptsForStarlark() {
+ return StarlarkList.immutableCopyOf(getLinkopts());
+ }
+
/**
- * Returns our own linkopts from the rule attribute. This determines linker
- * options to use when building this target and anything that depends on it.
+ * Returns our own linkopts from the rule attribute. This determines linker options to use when
+ * building this target and anything that depends on it.
*/
public ImmutableList<String> getLinkopts() {
Preconditions.checkState(hasAttribute("linkopts", Type.STRING_LIST));
@@ -217,6 +227,11 @@
return ImmutableList.copyOf(result);
}
+ @StarlarkMethod(name = "copts", structField = true, documented = false)
+ public Sequence<String> getCoptsForStarlark() {
+ return StarlarkList.immutableCopyOf(getCopts());
+ }
+
public ImmutableList<String> getCopts() {
if (!getCoptsFilter(ruleContext).passesFilter("-Wno-future-warnings")) {
ruleContext.attributeWarning(
@@ -263,6 +278,30 @@
return mapToListOfPairs(map);
}
+ @StarlarkMethod(name = "srcs", documented = false, structField = true)
+ public Sequence<Tuple> getSourcesForStarlark() {
+ List<Pair<Artifact, Label>> sources = getSources();
+ ImmutableList<Tuple> tupleList =
+ sources.stream().map(p -> Tuple.pair(p.first, p.second)).collect(toImmutableList());
+ return StarlarkList.immutableCopyOf(tupleList);
+ }
+
+ @StarlarkMethod(name = "private_hdrs", documented = false, structField = true)
+ public Sequence<Tuple> getPrivateHeaderForStarlark() {
+ return convertListPairToTuple(getPrivateHeaders());
+ }
+
+ @StarlarkMethod(name = "public_hdrs", documented = false, structField = true)
+ public Sequence<Tuple> getPublicHeaderForStarlark() {
+ return convertListPairToTuple(getHeaders());
+ }
+
+ private Sequence<Tuple> convertListPairToTuple(List<Pair<Artifact, Label>> listPair) {
+ ImmutableList<Tuple> tupleList =
+ listPair.stream().map(p -> Tuple.pair(p.first, p.second)).collect(toImmutableList());
+ return StarlarkList.immutableCopyOf(tupleList);
+ }
+
/**
* Returns a list of ({@link Artifact}, {@link Label}) pairs. Each pair represents an input source
* file and the label of the rule that generates it (or the label of the source file itself if it
@@ -335,9 +374,8 @@
return result.build();
}
- /**
- * Returns the C++ toolchain provider.
- */
+ /** Returns the C++ toolchain provider. */
+ @StarlarkMethod(name = "toolchain", documented = false, structField = true)
public CcToolchainProvider getToolchain() {
return ccToolchain;
}
@@ -355,6 +393,21 @@
return getHeaders(ruleContext);
}
+ @StarlarkMethod(
+ name = "report_invalid_options",
+ documented = false,
+ parameters = {
+ @Param(name = "ctx", positional = false, named = true),
+ })
+ public void reportInvalidOptionsForStarlark(StarlarkRuleContext starlarkRuleContext)
+ throws EvalException {
+ RuleContext ruleContext = starlarkRuleContext.getRuleContext();
+ reportInvalidOptions(ruleContext);
+ if (ruleContext.hasErrors()) {
+ throw new EvalException("Invalid options.");
+ }
+ }
+
public void reportInvalidOptions(RuleContext ruleContext) {
reportInvalidOptions(ruleContext, cppConfiguration, ccToolchain);
}
@@ -388,10 +441,17 @@
return null;
}
+ TransitiveInfoCollection toolchain;
+ if (ruleContext.attributes().has(CcToolchain.CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME)) {
+ toolchain = ruleContext.getPrerequisite(CcToolchain.CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME);
+ } else {
+ toolchain =
+ ruleContext.getPrerequisite(
+ CcToolchain.CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME_FOR_STARLARK);
+ }
+
try {
- return CcCommon.computeCcFlags(
- ruleContext,
- ruleContext.getPrerequisite(CcToolchain.CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME));
+ return CcCommon.computeCcFlags(ruleContext, toolchain);
} catch (RuleErrorException e) {
throw new ExpansionException(e.getMessage());
}
@@ -407,7 +467,7 @@
/** A filter that removes copts from a c++ compile action according to a nocopts regex. */
@AutoCodec
- static class CoptsFilter {
+ public static class CoptsFilter implements StarlarkValue {
private final Pattern noCoptsPattern;
private final boolean allPasses;
@@ -441,7 +501,8 @@
}
/** Returns copts filter built from the make variable expanded nocopts attribute. */
- CoptsFilter getCoptsFilter() {
+ @StarlarkMethod(name = "copts_filter", structField = true, documented = false)
+ public CoptsFilter getCoptsFilter() {
return getCoptsFilter(ruleContext);
}
@@ -482,18 +543,6 @@
}
}
- // TODO(bazel-team): calculating nocopts every time is not very efficient,
- // fix this after the rule migration. The problem is that in some cases we call this after
- // the RCT is created (so RuleContext is not accessible), in some cases during the creation.
- // It would probably make more sense to use TransitiveInfoProviders.
- /**
- * Returns true if the rule context has a nocopts regex that matches the given value, false
- * otherwise.
- */
- static boolean noCoptsMatches(String option, RuleContext ruleContext) {
- return !getCoptsFilter(ruleContext).passesFilter(option);
- }
-
private static final String DEFINES_ATTRIBUTE = "defines";
private static final String LOCAL_DEFINES_ATTRIBUTE = "local_defines";
@@ -509,6 +558,11 @@
return getDefinesFromAttribute(DEFINES_ATTRIBUTE);
}
+ @StarlarkMethod(name = "defines", structField = true, documented = false)
+ public Sequence<String> getDefinesForStarlark() {
+ return StarlarkList.immutableCopyOf(getDefines());
+ }
+
/**
* Returns a list of define tokens from "local_defines" attribute.
*
@@ -521,6 +575,11 @@
return getDefinesFromAttribute(LOCAL_DEFINES_ATTRIBUTE);
}
+ @StarlarkMethod(name = "local_defines", structField = true, documented = false)
+ public Sequence<String> getLocalDefinesForStarlark() {
+ return StarlarkList.immutableCopyOf(getNonTransitiveDefines());
+ }
+
private List<String> getDefinesFromAttribute(String attr) {
List<String> defines = new ArrayList<>();
@@ -558,6 +617,12 @@
return defines;
}
+ @StarlarkMethod(name = "loose_include_dirs", structField = true, documented = false)
+ public Sequence<String> getLooseIncludeDirsForStarlark() {
+ return StarlarkList.immutableCopyOf(
+ getLooseIncludeDirs().stream().map(PathFragment::toString).collect(toImmutableList()));
+ }
+
/**
* Determines a list of loose include directories that are only allowed to be referenced when
* headers checking is {@link HeadersCheckingMode#LOOSE}.
@@ -590,6 +655,12 @@
return result.build();
}
+ @StarlarkMethod(name = "system_include_dirs", structField = true, documented = false)
+ public Sequence<String> getSystemIncludeDirsForStarlark() {
+ return StarlarkList.immutableCopyOf(
+ getSystemIncludeDirs().stream().map(PathFragment::toString).collect(toImmutableList()));
+ }
+
List<PathFragment> getSystemIncludeDirs() {
boolean siblingRepositoryLayout = ruleContext.getConfiguration().isSiblingRepositoryLayout();
List<PathFragment> result = new ArrayList<>();
@@ -642,10 +713,11 @@
static NestedSet<Artifact> collectCompilationPrerequisites(
RuleContext ruleContext, CcCompilationContext ccCompilationContext) {
// TODO(bazel-team): Use ccCompilationContext.getCompilationPrerequisites() instead; note
- // that this will need cleaning up the prerequisites, as the {@code CcCompilationContext}
- // currently
- // collects them transitively (to get transitive headers), but source files are not transitive
- // compilation
+ // that this
+ // will
+ // need cleaning up the prerequisites, as the {@code CcCompilationContext} currently
+ // collects them
+ // transitively (to get transitive headers), but source files are not transitive compilation
// prerequisites.
NestedSetBuilder<Artifact> prerequisites = NestedSetBuilder.stableOrder();
if (ruleContext.attributes().has("srcs", BuildType.LABEL_LIST)) {
@@ -721,6 +793,23 @@
return ruleContext.getPrerequisiteArtifact("$def_parser");
}
+ @StarlarkMethod(
+ name = "instrumented_files_info",
+ documented = false,
+ parameters = {
+ @Param(name = "files", positional = false, named = true),
+ @Param(name = "with_base_line_coverage", positional = false, named = true),
+ })
+ public InstrumentedFilesInfo getInstrumentedFilesProviderForStarlark(
+ Sequence<?> files, boolean withBaselineCoverage) throws EvalException {
+ try {
+ return getInstrumentedFilesProvider(
+ Sequence.cast(files, Artifact.class, "files"), withBaselineCoverage);
+ } catch (RuleErrorException e) {
+ throw new EvalException(e);
+ }
+ }
+
/** Provides support for instrumentation. */
public InstrumentedFilesInfo getInstrumentedFilesProvider(
Iterable<Artifact> files, boolean withBaselineCoverage) throws RuleErrorException {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcStarlarkInternal.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcStarlarkInternal.java
index eeddf34..8741d79 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcStarlarkInternal.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcStarlarkInternal.java
@@ -18,9 +18,11 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.starlark.StarlarkRuleContext;
import com.google.devtools.build.lib.collect.nestedset.Depset;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import net.starlark.java.annot.Param;
import net.starlark.java.annot.StarlarkBuiltin;
import net.starlark.java.annot.StarlarkMethod;
+import net.starlark.java.eval.EvalException;
import net.starlark.java.eval.StarlarkValue;
/** Utility methods for Objc rules in Starlark Builtins */
@@ -43,4 +45,18 @@
CcCommon.collectCompilationPrerequisites(
starlarkRuleContext.getRuleContext(), compilationContext));
}
+
+ @StarlarkMethod(
+ name = "create_common",
+ documented = false,
+ parameters = {
+ @Param(name = "ctx", positional = false, named = true),
+ })
+ public CcCommon createCommon(StarlarkRuleContext starlarkRuleContext) throws EvalException {
+ try {
+ return new CcCommon(starlarkRuleContext.getRuleContext());
+ } catch (RuleErrorException e) {
+ throw new EvalException(e);
+ }
+ }
}