aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
authorGravatar Alex Humesky <ahumesky@google.com>2016-12-21 23:47:28 +0000
committerGravatar Klaus Aehlig <aehlig@google.com>2016-12-22 09:57:20 +0000
commit762a27c1c4e8eec7527caddd94168d57181726a6 (patch)
tree226ca92027d1542fb3fbdaf9358e3af87e1463bf /src/main
parentaa4ca94d7b44e6a776e46ed50d9b245058e8b9de (diff)
Exposes the Android split transition configuration to Skylark.
-- PiperOrigin-RevId: 142709934 MOS_MIGRATED_REVID=142709934
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java69
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java139
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java13
5 files changed, 167 insertions, 61 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
index 60d274787a..32469b5764 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
@@ -375,7 +375,9 @@ public abstract class DependencyResolver {
}
/**
- * Returns true if the rule's attribute triggers a split in this configuration.
+ * Returns the BuildOptions if the rule's attribute triggers a split in this configuration, or
+ * the empty collection if the attribute does not trigger a split transition or if the split
+ * transition does not apply.
*
* <p>Even though the attribute may have a split, splits don't have to apply in every
* configuration (see {@link Attribute.SplitTransition#split}).
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
index d782ce3e4b..46610f40d1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
@@ -25,6 +25,7 @@ import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
import com.google.devtools.build.lib.packages.Attribute.SkylarkComputedDefaultTemplate;
+import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
import com.google.devtools.build.lib.packages.AttributeValueSource;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.SkylarkAspect;
@@ -282,6 +283,8 @@ public final class SkylarkAttr {
builder.cfg(ConfigurationTransition.DATA);
} else if (trans.equals("host")) {
builder.cfg(ConfigurationTransition.HOST);
+ } else if (trans instanceof SplitTransition<?>) {
+ builder.cfg((SplitTransition<?>) trans);
} else if (!trans.equals("target")) {
throw new EvalException(ast.getLocation(),
"cfg must be either 'data', 'host', or 'target'.");
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 71aae066e3..3ed2301b93 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
@@ -15,6 +15,7 @@
package com.google.devtools.build.lib.rules;
import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
@@ -69,9 +70,11 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nullable;
@@ -119,6 +122,14 @@ public final class SkylarkRuleContext {
public static final String ATTR_DOC =
"A struct to access the values of the attributes. The values are provided by "
+ "the user (if not, a default value is used).";
+ public static final String SPLIT_ATTR_DOC =
+ "A struct to access the values of attributes with split configurations. If the attribute is "
+ + "a label list, the value of split_attr is a dict of the keys of the split (as strings) "
+ + "to lists of the ConfiguredTargets in that branch of the splitt. If the attribute is a "
+ + "label, then the value of split_attr is a dict of the keys of the split (as strings) "
+ + "to single ConfiguredTargets. Attributes with split configurations still appear in the "
+ + "attr struct, but their values will be single lists with all the branches of the split "
+ + "merged together.";
public static final String OUTPUTS_DOC =
"A <code>struct</code> containing all the output files."
+ " The struct is generated the following way:<br>"
@@ -151,6 +162,7 @@ public final class SkylarkRuleContext {
private final SkylarkDict<String, String> makeVariables;
private final SkylarkRuleAttributesCollection attributesCollection;
private final SkylarkRuleAttributesCollection ruleAttributesCollection;
+ private final SkylarkClassObject splitAttributes;
// TODO(bazel-team): we only need this because of the css_binary rule.
private final ImmutableMap<Artifact, Label> artifactsLabelMap;
@@ -228,6 +240,7 @@ public final class SkylarkRuleContext {
this.attributesCollection =
buildAttributesCollection(
attributes, ruleContext, attributeValueExtractorForRule(ruleContext));
+ this.splitAttributes = buildSplitAttributeInfo(attributes, ruleContext);
this.ruleAttributesCollection = null;
} else { // ASPECT
this.artifactsLabelMap = ImmutableMap.of();
@@ -237,6 +250,7 @@ public final class SkylarkRuleContext {
ruleContext.getAspectAttributes().values(),
ruleContext,
ATTRIBUTE_VALUE_EXTRACTOR_FOR_ASPECT);
+ this.splitAttributes = null;
this.ruleAttributesCollection =
buildAttributesCollection(
ruleContext.getRule().getAttributes(),
@@ -338,6 +352,52 @@ public final class SkylarkRuleContext {
executableRunfilesbuilder.build());
}
+ private static SkylarkClassObject buildSplitAttributeInfo(
+ Collection<Attribute> attributes, RuleContext ruleContext) {
+
+ ImmutableMap.Builder<String, Object> splitAttrInfos = ImmutableMap.builder();
+ for (Attribute attr : attributes) {
+
+ if (attr.hasSplitConfigurationTransition()) {
+
+ Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> splitPrereqs =
+ ruleContext.getSplitPrerequisites(attr.getName());
+
+ Map<Object, Object> splitPrereqsMap = new LinkedHashMap<>();
+ for (Entry<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> splitPrereq
+ : splitPrereqs.entrySet()) {
+
+ Object value;
+ if (attr.getType() == BuildType.LABEL) {
+ Preconditions.checkState(splitPrereq.getValue().size() == 1);
+ value = splitPrereq.getValue().get(0);
+ } else {
+ // BuildType.LABEL_LIST
+ value = SkylarkList.createImmutable(splitPrereq.getValue());
+ }
+
+ if (splitPrereq.getKey().isPresent()) {
+ splitPrereqsMap.put(splitPrereq.getKey().get(), value);
+ } else {
+ // If the split transition is not in effect, then the key will be missing since there's
+ // nothing to key on because the dependencies aren't split and getSplitPrerequisites()
+ // behaves like getPrerequisites(). This also means there should be only one entry in
+ // the map. Use None in Skylark to represent this.
+ Preconditions.checkState(splitPrereqs.size() == 1);
+ splitPrereqsMap.put(Runtime.NONE, value);
+ }
+ }
+
+ splitAttrInfos.put(attr.getPublicName(), SkylarkDict.copyOf(null, splitPrereqsMap));
+ }
+ }
+
+ return SkylarkClassObjectConstructor.STRUCT.create(
+ splitAttrInfos.build(),
+ "No attribute '%s' in split_attr. Make sure that this attribute is defined with a "
+ + "split configuration.");
+ }
+
@SkylarkModule(
name = "rule_attributes",
category = SkylarkModuleCategory.NONE,
@@ -458,6 +518,15 @@ public final class SkylarkRuleContext {
return attributesCollection.getAttr();
}
+ @SkylarkCallable(name = "split_attr", structField = true, doc = SPLIT_ATTR_DOC)
+ public SkylarkClassObject getSplitAttr() throws EvalException {
+ if (splitAttributes == null) {
+ throw new EvalException(
+ Location.BUILTIN, "'split_attr' is available only in rule implementations");
+ }
+ return splitAttributes;
+ }
+
/**
* <p>See {@link RuleContext#getExecutablePrerequisite(String, Mode)}.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 4240fb22d0..6943e95cce 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -51,8 +51,9 @@ import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.ProguardHelper;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
+import com.google.devtools.build.lib.syntax.Printer;
import com.google.devtools.build.lib.util.FileType;
-import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
@@ -188,72 +189,90 @@ public final class AndroidRuleClasses {
}
public static final SplitTransition<BuildOptions> ANDROID_SPLIT_TRANSITION =
- new SplitTransition<BuildOptions>() {
- @Override
- public boolean defaultsToSelf() {
- return true;
- }
+ new AndroidSplitTransition();
+
+ private static final class AndroidSplitTransition implements
+ SplitTransition<BuildOptions>, SkylarkValue {
- private void setCrosstoolToAndroid(BuildOptions output, BuildOptions input) {
- AndroidConfiguration.Options inputAndroidOptions =
- input.get(AndroidConfiguration.Options.class);
- AndroidConfiguration.Options outputAndroidOptions =
- output.get(AndroidConfiguration.Options.class);
-
- CppOptions cppOptions = output.get(CppOptions.class);
- if (inputAndroidOptions.androidCrosstoolTop != null
- && !cppOptions.crosstoolTop.equals(inputAndroidOptions.androidCrosstoolTop)) {
- if (cppOptions.hostCrosstoolTop == null) {
- cppOptions.hostCrosstoolTop = cppOptions.crosstoolTop;
- }
- cppOptions.crosstoolTop = inputAndroidOptions.androidCrosstoolTop;
- }
+ @Override
+ public boolean defaultsToSelf() {
+ return true;
+ }
- outputAndroidOptions.configurationDistinguisher = ConfigurationDistinguisher.ANDROID;
+ private static void setCrosstoolToAndroid(BuildOptions output, BuildOptions input) {
+ AndroidConfiguration.Options inputAndroidOptions =
+ input.get(AndroidConfiguration.Options.class);
+ AndroidConfiguration.Options outputAndroidOptions =
+ output.get(AndroidConfiguration.Options.class);
+
+ CppOptions cppOptions = output.get(CppOptions.class);
+ if (inputAndroidOptions.androidCrosstoolTop != null
+ && !cppOptions.crosstoolTop.equals(inputAndroidOptions.androidCrosstoolTop)) {
+ if (cppOptions.hostCrosstoolTop == null) {
+ cppOptions.hostCrosstoolTop = cppOptions.crosstoolTop;
}
+ cppOptions.crosstoolTop = inputAndroidOptions.androidCrosstoolTop;
+ }
- @Override
- public List<BuildOptions> split(BuildOptions buildOptions) {
- AndroidConfiguration.Options androidOptions =
- buildOptions.get(AndroidConfiguration.Options.class);
- CppOptions cppOptions = buildOptions.get(CppOptions.class);
- Label androidCrosstoolTop = androidOptions.androidCrosstoolTop;
- if (androidOptions.fatApkCpus.isEmpty()
- && (androidCrosstoolTop == null
- || androidCrosstoolTop.equals(cppOptions.crosstoolTop)
- || androidOptions.cpu.isEmpty())) {
- return ImmutableList.of();
- }
+ outputAndroidOptions.configurationDistinguisher = ConfigurationDistinguisher.ANDROID;
+ }
- if (androidOptions.fatApkCpus.isEmpty()) {
- BuildOptions splitOptions = buildOptions.clone();
- splitOptions.get(CppOptions.class).cppCompiler = androidOptions.cppCompiler;
- // getSplitPrerequisites() will complain if cpu is null after this transition,
- // so default to android_cpu.
- splitOptions.get(BuildConfiguration.Options.class).cpu = androidOptions.cpu;
- splitOptions.get(CppOptions.class).dynamicMode = androidOptions.dynamicMode;
- setCrosstoolToAndroid(splitOptions, buildOptions);
- return ImmutableList.of(splitOptions);
- }
+ @Override
+ public List<BuildOptions> split(BuildOptions buildOptions) {
- List<BuildOptions> result = new ArrayList<>();
- for (String cpu : ImmutableSortedSet.copyOf(androidOptions.fatApkCpus)) {
- BuildOptions splitOptions = buildOptions.clone();
- // Disable fat APKs for the child configurations.
- splitOptions.get(AndroidConfiguration.Options.class).fatApkCpus = ImmutableList.of();
-
- // Set the cpu & android_cpu.
- // TODO(bazel-team): --android_cpu doesn't follow --cpu right now; it should.
- splitOptions.get(AndroidConfiguration.Options.class).cpu = cpu;
- splitOptions.get(BuildConfiguration.Options.class).cpu = cpu;
- splitOptions.get(CppOptions.class).cppCompiler = androidOptions.cppCompiler;
- splitOptions.get(CppOptions.class).dynamicMode = androidOptions.dynamicMode;
- setCrosstoolToAndroid(splitOptions, buildOptions);
- result.add(splitOptions);
- }
- return result;
+ AndroidConfiguration.Options androidOptions =
+ buildOptions.get(AndroidConfiguration.Options.class);
+ CppOptions cppOptions = buildOptions.get(CppOptions.class);
+ Label androidCrosstoolTop = androidOptions.androidCrosstoolTop;
+
+ if (androidOptions.fatApkCpus.isEmpty()) {
+
+ if (androidOptions.cpu.isEmpty()
+ || androidCrosstoolTop == null
+ || androidCrosstoolTop.equals(cppOptions.crosstoolTop)) {
+ return ImmutableList.of();
+
+ } else {
+
+ BuildOptions splitOptions = buildOptions.clone();
+ splitOptions.get(CppOptions.class).cppCompiler = androidOptions.cppCompiler;
+ splitOptions.get(BuildConfiguration.Options.class).cpu = androidOptions.cpu;
+ splitOptions.get(CppOptions.class).dynamicMode = androidOptions.dynamicMode;
+ setCrosstoolToAndroid(splitOptions, buildOptions);
+ return ImmutableList.of(splitOptions);
}
- };
+
+ } else {
+
+ ImmutableList.Builder<BuildOptions> result = ImmutableList.builder();
+ for (String cpu : ImmutableSortedSet.copyOf(androidOptions.fatApkCpus)) {
+ BuildOptions splitOptions = buildOptions.clone();
+ // Disable fat APKs for the child configurations.
+ splitOptions.get(AndroidConfiguration.Options.class).fatApkCpus = ImmutableList.of();
+
+ // Set the cpu & android_cpu.
+ // TODO(bazel-team): --android_cpu doesn't follow --cpu right now; it should.
+ splitOptions.get(AndroidConfiguration.Options.class).cpu = cpu;
+ splitOptions.get(BuildConfiguration.Options.class).cpu = cpu;
+ splitOptions.get(CppOptions.class).cppCompiler = androidOptions.cppCompiler;
+ splitOptions.get(CppOptions.class).dynamicMode = androidOptions.dynamicMode;
+ setCrosstoolToAndroid(splitOptions, buildOptions);
+ result.add(splitOptions);
+ }
+ return result.build();
+ }
+ }
+
+ @Override
+ public boolean isImmutable() {
+ return true;
+ }
+
+ @Override
+ public void write(Appendable buffer, char quotationMark) {
+ Printer.append(buffer, "android_common.multi_cpu_configuration");
+ }
+ }
public static final FileType ANDROID_IDL = FileType.of(".aidl");
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java
index 462407bcdb..1024b074e9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.rules.android;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -26,6 +28,7 @@ import com.google.devtools.build.lib.vfs.PathFragment;
doc = "Common utilities and fucntionality related to Android rules."
)
public class AndroidSkylarkCommon {
+
@SkylarkCallable(
name = "resource_source_directory",
allowReturnNones = true,
@@ -38,4 +41,14 @@ public class AndroidSkylarkCommon {
public PathFragment getSourceDirectoryRelativePathFromResource(Artifact resource) {
return AndroidCommon.getSourceDirectoryRelativePathFromResource(resource);
}
+
+ @SkylarkCallable(
+ name = "multi_cpu_configuration",
+ doc = "A configuration for rule attributes that compiles native code according to "
+ + "the --fat_apk_cpu and --android_crosstool_top flags.",
+ structField = true
+ )
+ public SplitTransition<BuildOptions> getAndroidSplitTransition() {
+ return AndroidRuleClasses.ANDROID_SPLIT_TRANSITION;
+ }
}