From 3f8aac93ff0b2f06bc01b60614a265304aec177d Mon Sep 17 00:00:00 2001 From: Florian Weikert Date: Mon, 7 Sep 2015 12:06:02 +0000 Subject: Skylark: configuration fragments for host configuration can now be accessed via ctx.host_fragments. -- MOS_MIGRATED_REVID=102490502 --- .../build/lib/rules/SkylarkRuleClassFunctions.java | 137 ++++++++++++--------- .../build/lib/rules/SkylarkRuleContext.java | 35 ++++-- 2 files changed, 103 insertions(+), 69 deletions(-) (limited to 'src/main/java/com/google/devtools/build/lib/rules') 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 e2540342c7..42449c534a 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 @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.rules; import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.DATA; import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST; +import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.NONE; import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.Type.BOOLEAN; import static com.google.devtools.build.lib.packages.Type.INTEGER; @@ -33,7 +34,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.RunUnder; @@ -78,6 +79,7 @@ import com.google.devtools.build.lib.syntax.SkylarkSignature.Param; import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor; import com.google.devtools.build.lib.vfs.PathFragment; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -232,72 +234,91 @@ public class SkylarkRuleClassFunctions { @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. This is used for compatibility with existing rules."), - @Param(name = "fragments", type = SkylarkList.class, generic1 = String.class, + @Param(name = "fragments", type = SkylarkList.class, generic1 = String.class, defaultValue = "[]", - doc = "List of names of configuration fragments that the rule requires.")}, + 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.")}, useAst = true, useEnvironment = true) private static final BuiltinFunction rule = new BuiltinFunction("rule") { - @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces - // an Attribute.Builder instead of a Attribute.Builder but it's OK. - public BaseFunction invoke(BaseFunction implementation, Boolean test, Object attrs, - Object implicitOutputs, Boolean executable, Boolean outputToGenfiles, - SkylarkList fragments, FuncallExpression ast, Environment funcallEnv) - throws EvalException, ConversionException { - - funcallEnv.checkLoadingPhase("rule", ast.getLocation()); - RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL; - RuleClass parent = test ? testBaseRule : (executable ? binaryBaseRule : baseRule); - - // We'll set the name later, pass the empty string for now. - RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent); - - if (attrs != Runtime.NONE) { - for (Map.Entry attr : castMap( - attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) { - Attribute.Builder attrBuilder = (Attribute.Builder) attr.getValue(); - String attrName = attributeToNative(attr.getKey(), ast.getLocation(), - attrBuilder.hasLateBoundValue()); - builder.addOrOverrideAttribute(attrBuilder.build(attrName)); - } - } - if (executable || test) { - builder.addOrOverrideAttribute( - attr("$is_executable", BOOLEAN).value(true) - .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target") - .build()); - builder.setOutputsDefaultExecutable(); + @SuppressWarnings({"rawtypes", "unchecked"}) // castMap produces + // an Attribute.Builder instead of a Attribute.Builder but it's OK. + public BaseFunction invoke(BaseFunction implementation, Boolean test, Object attrs, + Object implicitOutputs, Boolean executable, Boolean outputToGenfiles, SkylarkList fragments, + SkylarkList hostFragments, FuncallExpression ast, Environment funcallEnv) + throws EvalException, ConversionException { + funcallEnv.checkLoadingPhase("rule", ast.getLocation()); + RuleClassType type = test ? RuleClassType.TEST : RuleClassType.NORMAL; + RuleClass parent = test ? testBaseRule : (executable ? binaryBaseRule : baseRule); + + // We'll set the name later, pass the empty string for now. + RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent); + + if (attrs != Runtime.NONE) { + for (Map.Entry attr : + castMap(attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) { + Attribute.Builder attrBuilder = (Attribute.Builder) attr.getValue(); + String attrName = + attributeToNative(attr.getKey(), ast.getLocation(), attrBuilder.hasLateBoundValue()); + builder.addOrOverrideAttribute(attrBuilder.build(attrName)); } + } + if (executable || test) { + builder.addOrOverrideAttribute( + attr("$is_executable", BOOLEAN) + .value(true) + .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target") + .build()); + builder.setOutputsDefaultExecutable(); + } - if (implicitOutputs != Runtime.NONE) { - if (implicitOutputs instanceof BaseFunction) { - BaseFunction func = (BaseFunction) implicitOutputs; - final SkylarkCallbackFunction callback = - new SkylarkCallbackFunction(func, ast, (SkylarkEnvironment) funcallEnv); - builder.setImplicitOutputsFunction( - new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation())); - } else { - builder.setImplicitOutputsFunction(new SkylarkImplicitOutputsFunctionWithMap( - ImmutableMap.copyOf(castMap(implicitOutputs, String.class, String.class, - "implicit outputs of the rule class")))); - } + if (implicitOutputs != Runtime.NONE) { + if (implicitOutputs instanceof BaseFunction) { + BaseFunction func = (BaseFunction) implicitOutputs; + final SkylarkCallbackFunction callback = + new SkylarkCallbackFunction(func, ast, (SkylarkEnvironment) funcallEnv); + builder.setImplicitOutputsFunction( + new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation())); + } else { + builder.setImplicitOutputsFunction( + new SkylarkImplicitOutputsFunctionWithMap(ImmutableMap.copyOf(castMap(implicitOutputs, + String.class, String.class, "implicit outputs of the rule class")))); } + } - if (outputToGenfiles) { - builder.setOutputToGenfiles(); - } + if (outputToGenfiles) { + builder.setOutputToGenfiles(); + } - if (!fragments.isEmpty()) { - builder.requiresConfigurationFragments( - new SkylarkModuleNameResolver(), - Iterables.toArray(castList(fragments, String.class), String.class)); - } + registerRequiredFragments(fragments, hostFragments, builder); - builder.setConfiguredTargetFunction(implementation); - builder.setRuleDefinitionEnvironment( - ((SkylarkEnvironment) funcallEnv).getGlobalEnvironment()); - return new RuleFunction(builder, type); - } - }; + builder.setConfiguredTargetFunction(implementation); + builder.setRuleDefinitionEnvironment( + ((SkylarkEnvironment) funcallEnv).getGlobalEnvironment()); + return new RuleFunction(builder, type); + } + + private void registerRequiredFragments( + SkylarkList fragments, SkylarkList hostFragments, RuleClass.Builder builder) { + Map> map = new HashMap<>(); + addFragmentsToMap(map, fragments, NONE); // NONE represents target configuration + addFragmentsToMap(map, hostFragments, HOST); + + builder.requiresConfigurationFragments(new SkylarkModuleNameResolver(), map); + } + + private void addFragmentsToMap(Map> map, + SkylarkList fragments, ConfigurationTransition config) { + if (!fragments.isEmpty()) { + map.put(config, ImmutableSet.copyOf(castList(fragments, String.class))); + } + } + }; // This class is needed for testing static final class RuleFunction extends BaseFunction { 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 af962f076a..d3909fbcf8 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.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.FragmentCollection; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.packages.Attribute; +import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition; import com.google.devtools.build.lib.packages.ImplicitOutputsFunction; import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunction; import com.google.devtools.build.lib.packages.OutputFile; @@ -94,9 +95,11 @@ public final class SkylarkRuleContext { }); private final RuleContext ruleContext; - + private final FragmentCollection fragments; + private final FragmentCollection hostFragments; + // TODO(bazel-team): support configurable attributes. private final SkylarkClassObject attrObject; @@ -120,7 +123,8 @@ public final class SkylarkRuleContext { */ public SkylarkRuleContext(RuleContext ruleContext) throws EvalException { this.ruleContext = Preconditions.checkNotNull(ruleContext); - fragments = new FragmentCollection(ruleContext); + fragments = new FragmentCollection(ruleContext, ConfigurationTransition.NONE); + hostFragments = new FragmentCollection(ruleContext, ConfigurationTransition.HOST); HashMap outputsBuilder = new HashMap<>(); if (ruleContext.getRule().getRuleClassObject().outputsDefaultExecutable()) { @@ -326,19 +330,28 @@ public final class SkylarkRuleContext { return ruleContext.getLabel(); } - @SkylarkCallable( - name = "fragments", - structField = true, - doc = - "Allows access to configuration fragments. Possible fields are cpp, " - + "java and jvm. " - + "However, rules have to declare their required fragments in order to access them " - + "(see here)." - ) + @SkylarkCallable(name = "fragments", structField = true, + doc = + "Allows access to configuration fragments in target configuration. " + + "Possible fields are cpp, " + + "java and jvm. " + + "However, rules have to declare their required fragments in order to access them " + + "(see here).") public FragmentCollection getFragments() { return fragments; } + @SkylarkCallable(name = "host_fragments", structField = true, + doc = + "Allows access to configuration fragments in host configuration. " + + "Possible fields are cpp, " + + "java and jvm. " + + "However, rules have to declare their required fragments in order to access them " + + "(see here).") + public FragmentCollection getHostFragments() { + return hostFragments; + } + @SkylarkCallable(name = "configuration", structField = true, doc = "Returns the default configuration. See the " + "configuration type for more details.") -- cgit v1.2.3