Add toolchains data to RuleClass and RuleContext.
Also expose both sides to Skylark.
Part of #2219.
Change-Id: I4d749dd9981fe33f75310acb0ec3927cff6f28fe
PiperOrigin-RevId: 156340638
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 3e753e6..37e20c9 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -591,6 +591,7 @@
":util",
":vfs",
"//src/main/java/com/google/devtools/build/lib/actions",
+ "//src/main/java/com/google/devtools/build/lib/analysis/platform",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
"//src/main/java/com/google/devtools/build/lib/causes",
"//src/main/java/com/google/devtools/build/lib/cmdline",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index a6c43d4..f1e1db2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -167,6 +167,7 @@
private final ErrorReporter reporter;
private final ImmutableBiMap<String, Class<? extends TransitiveInfoProvider>>
skylarkProviderRegistry;
+ private final ToolchainContext toolchainContext;
private ActionOwner actionOwner;
@@ -197,6 +198,8 @@
this.skylarkProviderRegistry = builder.skylarkProviderRegistry;
this.hostConfiguration = builder.hostConfiguration;
reporter = builder.reporter;
+ // TODO(katre): Populate the actual selected toolchains.
+ this.toolchainContext = new ToolchainContext(null);
}
private ImmutableSet<String> getEnabledFeatures() {
@@ -1121,6 +1124,10 @@
}
}
+ public ToolchainContext getToolchainContext() {
+ return toolchainContext;
+ }
+
private void checkAttribute(String attributeName, Mode mode) {
Attribute attributeDefinition = attributes.getAttributeDefinition(attributeName);
if (attributeDefinition == null) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
new file mode 100644
index 0000000..c4c9a9f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ToolchainContext.java
@@ -0,0 +1,38 @@
+// Copyright 2017 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.analysis;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
+import com.google.devtools.build.lib.packages.ClassObjectConstructor;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import java.util.Map;
+import javax.annotation.Nullable;
+
+/** Contains toolchain-related information needed for a {@link RuleContext}. */
+public class ToolchainContext {
+ private final ImmutableMap<ClassObjectConstructor.Key, ToolchainInfo> toolchains;
+
+ public ToolchainContext(@Nullable Map<ClassObjectConstructor.Key, ToolchainInfo> toolchains) {
+ this.toolchains =
+ toolchains == null
+ ? ImmutableMap.<ClassObjectConstructor.Key, ToolchainInfo>of()
+ : ImmutableMap.copyOf(toolchains);
+ }
+
+ public SkylarkDict<ClassObjectConstructor.Key, ToolchainInfo> collectToolchains() {
+ return SkylarkDict.<ClassObjectConstructor.Key, ToolchainInfo>copyOf(null, toolchains);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index 9293b09..5a5b58d 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -508,6 +508,7 @@
private boolean supportsConstraintChecking = true;
private final Map<String, Attribute> attributes = new LinkedHashMap<>();
+ private final List<ClassObjectConstructor.Key> requiredToolchains = new ArrayList<>();
/**
* Constructs a new {@code RuleClassBuilder} using all attributes from all
@@ -618,6 +619,7 @@
ruleDefinitionEnvironmentHashCode,
configurationFragmentPolicy.build(),
supportsConstraintChecking,
+ requiredToolchains,
attributes.values().toArray(new Attribute[0]));
}
@@ -998,6 +1000,11 @@
return this;
}
+ public Builder addRequiredToolchain(ClassObjectConstructor.Key toolchain) {
+ this.requiredToolchains.add(toolchain);
+ return this;
+ }
+
/**
* Returns an Attribute.Builder object which contains a replica of the
* same attribute in the parent rule if exists.
@@ -1118,26 +1125,27 @@
*/
private final boolean supportsConstraintChecking;
+ private final ImmutableList<ClassObjectConstructor.Key> requiredToolchains;
+
/**
- * Constructs an instance of RuleClass whose name is 'name', attributes
- * are 'attributes'. The {@code srcsAllowedFiles} determines which types of
- * files are allowed as parameters to the "srcs" attribute; rules are always
- * allowed. For the "deps" attribute, there are four cases:
+ * Constructs an instance of RuleClass whose name is 'name', attributes are 'attributes'. The
+ * {@code srcsAllowedFiles} determines which types of files are allowed as parameters to the
+ * "srcs" attribute; rules are always allowed. For the "deps" attribute, there are four cases:
+ *
* <ul>
- * <li>if the parameter is a file, it is allowed if its file type is given
- * in {@code depsAllowedFiles},
- * <li>if the parameter is a rule and the rule class is accepted by
- * {@code depsAllowedRules}, then it is allowed,
- * <li>if the parameter is a rule and the rule class is not accepted by
- * {@code depsAllowedRules}, but accepted by
- * {@code depsAllowedRulesWithWarning}, then it is allowed, but
- * triggers a warning;
+ * <li>if the parameter is a file, it is allowed if its file type is given in {@code
+ * depsAllowedFiles},
+ * <li>if the parameter is a rule and the rule class is accepted by {@code depsAllowedRules},
+ * then it is allowed,
+ * <li>if the parameter is a rule and the rule class is not accepted by {@code
+ * depsAllowedRules}, but accepted by {@code depsAllowedRulesWithWarning}, then it is
+ * allowed, but triggers a warning;
* <li>all other parameters trigger an error.
* </ul>
*
- * <p>The {@code depsAllowedRules} predicate should have a {@code toString}
- * method which returns a plain English enumeration of the allowed rule class
- * names, if it does not allow all rule classes.
+ * <p>The {@code depsAllowedRules} predicate should have a {@code toString} method which returns a
+ * plain English enumeration of the allowed rule class names, if it does not allow all rule
+ * classes.
*/
@VisibleForTesting
RuleClass(
@@ -1165,6 +1173,7 @@
String ruleDefinitionEnvironmentHashCode,
ConfigurationFragmentPolicy configurationFragmentPolicy,
boolean supportsConstraintChecking,
+ List<ClassObjectConstructor.Key> requiredToolchains,
Attribute... attributes) {
this.name = name;
this.isSkylark = isSkylark;
@@ -1193,6 +1202,7 @@
this.outputsDefaultExecutable = outputsDefaultExecutable;
this.configurationFragmentPolicy = configurationFragmentPolicy;
this.supportsConstraintChecking = supportsConstraintChecking;
+ this.requiredToolchains = ImmutableList.copyOf(requiredToolchains);
// Create the index and collect non-configurable attributes.
int index = 0;
@@ -2002,6 +2012,10 @@
return outputsDefaultExecutable;
}
+ public ImmutableList<ClassObjectConstructor.Key> getRequiredToolchains() {
+ return requiredToolchains;
+ }
+
public static boolean isThirdPartyPackage(PackageIdentifier packageIdentifier) {
if (!packageIdentifier.getRepository().isMain()) {
return false;
diff --git a/src/main/java/com/google/devtools/build/lib/packages/ToolchainConstructor.java b/src/main/java/com/google/devtools/build/lib/packages/ToolchainConstructor.java
index fe21f43e..13a965e 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/ToolchainConstructor.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/ToolchainConstructor.java
@@ -14,13 +14,14 @@
package com.google.devtools.build.lib.packages;
import com.google.devtools.build.lib.packages.ClassObjectConstructor.Key;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
/**
* Constructor that can be used to generate toolchains. The key returned by {@link #getKey()} is a
* serializable representation of the constructor and serves to identify toolchains of the same
* type.
*/
-public interface ToolchainConstructor {
+public interface ToolchainConstructor extends SkylarkValue {
Key getKey();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index 02b304f..083cb92 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -70,6 +70,7 @@
import com.google.devtools.build.lib.packages.SkylarkExportable;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.packages.TestSize;
+import com.google.devtools.build.lib.packages.ToolchainConstructor;
import com.google.devtools.build.lib.rules.SkylarkAttr.Descriptor;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
@@ -266,122 +267,132 @@
}
};
-
// TODO(bazel-team): implement attribute copy and other rule properties
@SkylarkSignature(
- name = "rule",
- doc =
- "Creates a new rule. Store it in a global value, so that it can be loaded and called "
- + "from BUILD files.",
- returnType = BaseFunction.class,
- parameters = {
- @Param(
- name = "implementation",
- type = BaseFunction.class,
- doc =
- "the function implementing this rule, must have exactly one parameter: "
- + "<a href=\"ctx.html\">ctx</a>. The function is called during the analysis "
- + "phase for each instance of the rule. It can access the attributes "
- + "provided by the user. It must create actions to generate all the declared "
- + "outputs."
- ),
- @Param(
- name = "test",
- type = Boolean.class,
- defaultValue = "False",
- doc =
- "Whether this rule is a test rule. "
- + "If True, the rule must end with <code>_test</code> (otherwise it must "
- + "not), and there must be an action that generates "
- + "<code>ctx.outputs.executable</code>."
- ),
- @Param(
- name = "attrs",
- type = SkylarkDict.class,
- noneable = true,
- defaultValue = "None",
- doc =
- "dictionary to declare all the attributes of the rule. It maps from an attribute "
- + "name to an attribute object (see <a href=\"attr.html\">attr</a> module). "
- + "Attributes starting with <code>_</code> are private, and can be used to "
- + "add an implicit dependency on a label. The attribute <code>name</code> is "
- + "implicitly added and must not be specified. Attributes "
- + "<code>visibility</code>, <code>deprecation</code>, <code>tags</code>, "
- + "<code>testonly</code>, and <code>features</code> are implicitly added and "
- + "cannot be overriden."
- ),
- // TODO(bazel-team): need to give the types of these builtin attributes
- @Param(
- name = "outputs",
- type = SkylarkDict.class,
- callbackEnabled = true,
- noneable = true,
- defaultValue = "None",
- doc =
- "outputs of this rule. "
- + "It is a dictionary mapping from string to a template name. "
- + "For example: <code>{\"ext\": \"%{name}.ext\"}</code>. <br>"
- + "The dictionary key becomes an attribute in <code>ctx.outputs</code>. "
- + "Similar to computed dependency rule attributes, you can also specify the "
- + "name of a function that returns the dictionary. This function can access "
- + "all rule attributes that are listed as parameters in its function "
- + "signature. For example, <code>outputs = _my_func</code> with "
- + "<code>def _my_func(srcs, deps):</code> has access to the attributes "
- + "'srcs' and 'deps' (if defined)."
- ),
- @Param(
- name = "executable",
- type = Boolean.class,
- defaultValue = "False",
- doc =
- "whether this rule is marked as executable or not. If True, "
- + "there must be an action that generates "
- + "<code>ctx.outputs.executable</code>."
- ),
- @Param(
- name = "output_to_genfiles",
- type = Boolean.class,
- defaultValue = "False",
- doc =
- "If true, the files will be generated in the genfiles directory instead of the "
- + "bin directory. Unless you need it for compatibility with existing rules "
- + "(e.g. when generating header files for C++), do not set this flag."
- ),
- @Param(
- name = "fragments",
- type = SkylarkList.class,
- generic1 = String.class,
- defaultValue = "[]",
- doc =
- "List of names of configuration fragments that the rule requires "
- + "in target configuration."
- ),
- @Param(
- name = "host_fragments",
- type = SkylarkList.class,
- generic1 = String.class,
- defaultValue = "[]",
- doc =
- "List of names of configuration fragments that the rule requires "
- + "in host configuration."
- ),
- @Param(
- name = "_skylark_testable",
- type = Boolean.class,
- defaultValue = "False",
- doc =
- "<i>(Experimental)</i><br/><br/>"
- + "If true, this rule will expose its actions for inspection by rules that "
- + "depend on it via an <a href=\"globals.html#Actions\">Actions</a> "
- + "provider. The provider is also available to the rule itself by calling "
- + "<a href=\"ctx.html#created_actions\">ctx.created_actions()</a>."
- + "<br/><br/>"
- + "This should only be used for testing the analysis-time behavior of "
- + "Skylark rules. This flag may be removed in the future."
- )
- },
- useAst = true,
- useEnvironment = true
+ name = "rule",
+ doc =
+ "Creates a new rule. Store it in a global value, so that it can be loaded and called "
+ + "from BUILD files.",
+ returnType = BaseFunction.class,
+ parameters = {
+ @Param(
+ name = "implementation",
+ type = BaseFunction.class,
+ doc =
+ "the function implementing this rule, must have exactly one parameter: "
+ + "<a href=\"ctx.html\">ctx</a>. The function is called during the analysis "
+ + "phase for each instance of the rule. It can access the attributes "
+ + "provided by the user. It must create actions to generate all the declared "
+ + "outputs."
+ ),
+ @Param(
+ name = "test",
+ type = Boolean.class,
+ defaultValue = "False",
+ doc =
+ "Whether this rule is a test rule. "
+ + "If True, the rule must end with <code>_test</code> (otherwise it must "
+ + "not), and there must be an action that generates "
+ + "<code>ctx.outputs.executable</code>."
+ ),
+ @Param(
+ name = "attrs",
+ type = SkylarkDict.class,
+ noneable = true,
+ defaultValue = "None",
+ doc =
+ "dictionary to declare all the attributes of the rule. It maps from an attribute "
+ + "name to an attribute object (see <a href=\"attr.html\">attr</a> module). "
+ + "Attributes starting with <code>_</code> are private, and can be used to "
+ + "add an implicit dependency on a label. The attribute <code>name</code> is "
+ + "implicitly added and must not be specified. Attributes "
+ + "<code>visibility</code>, <code>deprecation</code>, <code>tags</code>, "
+ + "<code>testonly</code>, and <code>features</code> are implicitly added and "
+ + "cannot be overriden."
+ ),
+ // TODO(bazel-team): need to give the types of these builtin attributes
+ @Param(
+ name = "outputs",
+ type = SkylarkDict.class,
+ callbackEnabled = true,
+ noneable = true,
+ defaultValue = "None",
+ doc =
+ "outputs of this rule. "
+ + "It is a dictionary mapping from string to a template name. "
+ + "For example: <code>{\"ext\": \"%{name}.ext\"}</code>. <br>"
+ + "The dictionary key becomes an attribute in <code>ctx.outputs</code>. "
+ + "Similar to computed dependency rule attributes, you can also specify the "
+ + "name of a function that returns the dictionary. This function can access "
+ + "all rule attributes that are listed as parameters in its function "
+ + "signature. For example, <code>outputs = _my_func</code> with "
+ + "<code>def _my_func(srcs, deps):</code> has access to the attributes "
+ + "'srcs' and 'deps' (if defined)."
+ ),
+ @Param(
+ name = "executable",
+ type = Boolean.class,
+ defaultValue = "False",
+ doc =
+ "whether this rule is marked as executable or not. If True, "
+ + "there must be an action that generates "
+ + "<code>ctx.outputs.executable</code>."
+ ),
+ @Param(
+ name = "output_to_genfiles",
+ type = Boolean.class,
+ defaultValue = "False",
+ doc =
+ "If true, the files will be generated in the genfiles directory instead of the "
+ + "bin directory. Unless you need it for compatibility with existing rules "
+ + "(e.g. when generating header files for C++), do not set this flag."
+ ),
+ @Param(
+ name = "fragments",
+ type = SkylarkList.class,
+ generic1 = String.class,
+ defaultValue = "[]",
+ doc =
+ "List of names of configuration fragments that the rule requires "
+ + "in target configuration."
+ ),
+ @Param(
+ name = "host_fragments",
+ type = SkylarkList.class,
+ generic1 = String.class,
+ defaultValue = "[]",
+ doc =
+ "List of names of configuration fragments that the rule requires "
+ + "in host configuration."
+ ),
+ @Param(
+ name = "_skylark_testable",
+ type = Boolean.class,
+ defaultValue = "False",
+ doc =
+ "<i>(Experimental)</i><br/><br/>"
+ + "If true, this rule will expose its actions for inspection by rules that "
+ + "depend on it via an <a href=\"globals.html#Actions\">Actions</a> "
+ + "provider. The provider is also available to the rule itself by calling "
+ + "<a href=\"ctx.html#created_actions\">ctx.created_actions()</a>."
+ + "<br/><br/>"
+ + "This should only be used for testing the analysis-time behavior of "
+ + "Skylark rules. This flag may be removed in the future."
+ ),
+ @Param(
+ name = "toolchains",
+ type = SkylarkList.class,
+ generic1 = ToolchainConstructor.class,
+ defaultValue = "[]",
+ doc =
+ "<i>(Experimental)</i><br/><br/>"
+ + "If set, the set of toolchains this rule requires. Toolchains will be "
+ + "found by checking the current platform, and provided to the rule "
+ + "implementation via <code>ctx.toolchain</code>."
+ )
+ },
+ useAst = true,
+ useEnvironment = true
)
private static final BuiltinFunction rule =
new BuiltinFunction("rule") {
@@ -397,6 +408,7 @@
SkylarkList fragments,
SkylarkList hostFragments,
Boolean skylarkTestable,
+ SkylarkList<ToolchainConstructor> toolchains,
FuncallExpression ast,
Environment funcallEnv)
throws EvalException, ConversionException {
@@ -455,6 +467,11 @@
hostFragments.getContents(String.class, "host_fragments"));
builder.setConfiguredTargetFunction(implementation);
builder.setRuleDefinitionEnvironment(funcallEnv);
+
+ for (ToolchainConstructor toolchain : toolchains) {
+ builder.addRequiredToolchain(toolchain.getKey());
+ }
+
return new RuleFunction(builder, type, attributes, ast.getLocation());
}
};
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index 009b6e4..90c121b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -36,6 +36,7 @@
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.FragmentCollection;
+import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Location;
@@ -179,6 +180,7 @@
private SkylarkRuleAttributesCollection attributesCollection;
private SkylarkRuleAttributesCollection ruleAttributesCollection;
private SkylarkClassObject splitAttributes;
+ private SkylarkDict<ClassObjectConstructor.Key, ToolchainInfo> toolchains;
// TODO(bazel-team): we only need this because of the css_binary rule.
private ImmutableMap<Artifact, Label> artifactsLabelMap;
@@ -260,6 +262,7 @@
this, attributes, ruleContext, attributeValueExtractorForRule(ruleContext));
this.splitAttributes = buildSplitAttributeInfo(attributes, ruleContext);
this.ruleAttributesCollection = null;
+ toolchains = ruleContext.getToolchainContext().collectToolchains();
} else { // ASPECT
this.artifactsLabelMap = ImmutableMap.of();
this.outputsObject = null;
@@ -276,6 +279,8 @@
ruleContext.getRule().getAttributes(),
ruleContext,
attributeValueExtractorForRule(ruleContext));
+ // TODO(katre): Collect toolchains for aspects.
+ toolchains = null;
}
makeVariables = ruleContext.getConfigurationMakeVariableContext().collectMakeVariables();
@@ -297,6 +302,7 @@
splitAttributes = null;
artifactsLabelMap = null;
outputsObject = null;
+ toolchains = null;
}
public void checkMutable(String attrName) throws EvalException {
@@ -810,6 +816,17 @@
return makeVariables;
}
+ @SkylarkCallable(structField = true, doc = "Toolchains required for this rule.")
+ public SkylarkDict<ClassObjectConstructor.Key, ToolchainInfo> toolchains() throws EvalException {
+ checkMutable("toolchains");
+ if (ruleAttributesCollection != null) {
+ // TODO(katre): Support toolchains on aspects.
+ throw new EvalException(
+ Location.BUILTIN, "'toolchains' is not available in aspect implementations");
+ }
+ return toolchains;
+ }
+
@Override
public String toString() {
return ruleLabelCanonicalName;
diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
index b0a23b4..63ccc24 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
@@ -908,6 +908,7 @@
.setMissingFragmentPolicy(missingFragmentPolicy)
.build(),
supportsConstraintChecking,
+ /*requiredToolchains=*/ ImmutableList.<ClassObjectConstructor.Key>of(),
attributes);
}
@@ -1040,4 +1041,21 @@
// expected
}
}
+
+ @Test
+ public void testRequiredToolchains() throws Exception {
+ RuleClass.Builder ruleClassBuilder =
+ new RuleClass.Builder("ruleClass", RuleClassType.NORMAL, false)
+ .factory(DUMMY_CONFIGURED_TARGET_FACTORY)
+ .add(attr("tags", STRING_LIST));
+
+ ClassObjectConstructor.Key toolchain1 = new ClassObjectConstructor.Key() {};
+ ClassObjectConstructor.Key toolchain2 = new ClassObjectConstructor.Key() {};
+ ruleClassBuilder.addRequiredToolchain(toolchain1);
+ ruleClassBuilder.addRequiredToolchain(toolchain2);
+
+ RuleClass ruleClass = ruleClassBuilder.build();
+
+ assertThat(ruleClass.getRequiredToolchains()).containsExactly(toolchain1, toolchain2).inOrder();
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/BUILD b/src/test/java/com/google/devtools/build/lib/skylark/BUILD
index 0cd4824..52a35a8 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/skylark/BUILD
@@ -20,6 +20,7 @@
"//src/main/java/com/google/devtools/build/lib:packages",
"//src/main/java/com/google/devtools/build/lib:vfs",
"//src/main/java/com/google/devtools/build/lib/actions",
+ "//src/main/java/com/google/devtools/build/lib/rules/platform",
"//src/test/java/com/google/devtools/build/lib:analysis_testutil",
"//src/test/java/com/google/devtools/build/lib:foundations_testutil",
"//src/test/java/com/google/devtools/build/lib:syntax_testutil",
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
index 8852be8..2be126b 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
@@ -42,6 +42,7 @@
import com.google.devtools.build.lib.packages.SkylarkClassObject;
import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor;
import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
+import com.google.devtools.build.lib.packages.ToolchainConstructor;
import com.google.devtools.build.lib.rules.SkylarkAttr;
import com.google.devtools.build.lib.rules.SkylarkAttr.Descriptor;
import com.google.devtools.build.lib.rules.SkylarkFileType;
@@ -1377,5 +1378,15 @@
+ "provided.");
}
}
-}
+ @Test
+ public void testRuleAddToolchain() throws Exception {
+ evalAndExport(
+ "my_toolchain_type = platform_common.toolchain_type()",
+ "def impl(ctx): return None",
+ "r1 = rule(impl, toolchains=[my_toolchain_type])");
+ ToolchainConstructor toolchain = (ToolchainConstructor) lookup("my_toolchain_type");
+ RuleClass c = ((RuleFunction) lookup("r1")).getRuleClass();
+ assertThat(c.getRequiredToolchains()).containsExactly(toolchain.getKey());
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java b/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java
index 8c86c07..e416997 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/util/SkylarkTestCase.java
@@ -26,12 +26,14 @@
import com.google.devtools.build.lib.packages.PackageFactory.PackageContext;
import com.google.devtools.build.lib.rules.SkylarkModules;
import com.google.devtools.build.lib.rules.SkylarkRuleContext;
+import com.google.devtools.build.lib.rules.platform.PlatformCommon;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.Environment.Phase;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.SkylarkUtils;
import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import com.google.devtools.build.lib.testutil.TestConstants;
+import java.util.List;
import org.junit.Before;
/**
@@ -52,10 +54,15 @@
return new EvaluationTestCase() {
@Override
public Environment newEnvironment() throws Exception {
+ List<Class<?>> modules =
+ new ImmutableList.Builder<Class<?>>()
+ .addAll(SkylarkModules.MODULES)
+ .add(PlatformCommon.class)
+ .build();
Environment env =
Environment.builder(mutability)
.setEventHandler(getEventHandler())
- .setGlobals(SkylarkModules.getGlobals(SkylarkModules.MODULES))
+ .setGlobals(SkylarkModules.getGlobals(modules))
.setPhase(Phase.LOADING)
.build()
.setupDynamic(