Exposes the Android split transition configuration to Skylark.

--
PiperOrigin-RevId: 142709934
MOS_MIGRATED_REVID=142709934
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 60d2747..32469b5 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 @@
   }
 
   /**
-   * 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 d782ce3..46610f4 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.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 @@
         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 71aae06..3ed2301 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.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 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 @@
   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 @@
       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 @@
               ruleContext.getAspectAttributes().values(),
               ruleContext,
               ATTRIBUTE_VALUE_EXTRACTOR_FOR_ASPECT);
+      this.splitAttributes = null;
       this.ruleAttributesCollection =
           buildAttributesCollection(
               ruleContext.getRule().getAttributes(),
@@ -338,6 +352,52 @@
         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 @@
     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 4240fb2..6943e95 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.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 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 {
+
+    @Override
+    public boolean defaultsToSelf() {
+      return true;
+    }
+
+    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;
+      }
+
+      outputAndroidOptions.configurationDistinguisher = ConfigurationDistinguisher.ANDROID;
+    }
+
+    @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()) {
+
+        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);
         }
 
-        private void setCrosstoolToAndroid(BuildOptions output, BuildOptions input) {
-          AndroidConfiguration.Options inputAndroidOptions =
-              input.get(AndroidConfiguration.Options.class);
-          AndroidConfiguration.Options outputAndroidOptions =
-              output.get(AndroidConfiguration.Options.class);
+      } else {
 
-          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;
-          }
+        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();
 
-          outputAndroidOptions.configurationDistinguisher = ConfigurationDistinguisher.ANDROID;
+          // 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 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();
-          }
+    @Override
+    public boolean isImmutable() {
+      return true;
+    }
 
-          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);
-          }
-
-          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;
-        }
-      };
+    @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 462407b..1024b07 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 @@
   doc = "Common utilities and fucntionality related to Android rules."
 )
 public class AndroidSkylarkCommon {
+
   @SkylarkCallable(
     name = "resource_source_directory",
     allowReturnNones = true,
@@ -38,4 +41,14 @@
   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;
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 40c40b9..75e43c1 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -25,6 +25,7 @@
     srcs = glob(["**"]) + [
         "//src/test/java/com/google/devtools/build/lib/skylark:srcs",
         "//src/test/java/com/google/devtools/build/lib/skyframe:srcs",
+        "//src/test/java/com/google/devtools/build/lib/rules/android:srcs",
         "//src/test/java/com/google/devtools/build/lib/rules/repository:srcs",
         "//src/test/java/com/google/devtools/build/lib/bazel/repository:srcs",
         "//src/test/java/com/google/devtools/build/lib/buildeventstream/transports:srcs",
@@ -555,6 +556,7 @@
     srcs = glob([
         "packages/util/*.java",
     ]),
+    resources = ["packages/util/MOCK_ANDROID_CROSSTOOL"],
     deps = [
         ":foundations_testutil",
         ":testutil",
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockAndroidSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockAndroidSupport.java
new file mode 100644
index 0000000..99cba90
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockAndroidSupport.java
@@ -0,0 +1,36 @@
+// Copyright 2016 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.packages.util;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.util.ResourceFileLoader;
+import java.io.IOException;
+
+/**
+ * Mocks out Android dependencies for testing.
+ */
+public class BazelMockAndroidSupport {
+
+  public static void setupNdk(MockToolsConfig config) throws IOException {
+    new Crosstool(config, "android/crosstool")
+        .setCrosstoolFile(
+            /*version=*/ "mock_version",
+            ResourceFileLoader.loadResource(
+                BazelMockAndroidSupport.class, "MOCK_ANDROID_CROSSTOOL"))
+        .setSupportedArchs(ImmutableList.of("x86", "armeabi-v7a"))
+        .setSupportsHeaderParsing(false)
+        .write();
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/MOCK_ANDROID_CROSSTOOL b/src/test/java/com/google/devtools/build/lib/packages/util/MOCK_ANDROID_CROSSTOOL
new file mode 100644
index 0000000..f63bcb2
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/MOCK_ANDROID_CROSSTOOL
@@ -0,0 +1,126 @@
+major_version: "18"
+minor_version: "0"
+default_target_cpu: "armeabi-v7a"
+
+default_toolchain {
+  cpu: "armeabi-v7a"
+  toolchain_identifier: "armeabi-v7a"
+}
+
+default_toolchain {
+  cpu: "x86"
+  toolchain_identifier: "x86"
+}
+
+toolchain {
+  toolchain_identifier: "armeabi-v7a"
+  host_system_name: "x86"
+  target_system_name: "arm-linux-androideabi"
+
+  target_cpu: "armeabi-v7a"
+
+  target_libc: "local"
+  compiler: "gcc"
+  abi_version: "armeabi-v7a"
+  abi_libc_version: "r7"
+  tool_path {
+    name: "gcc"
+    path: "arm/bin/arm-linux-androideabi-gcc"
+  }
+  tool_path {
+    name: "ar"
+    path: "arm/bin/arm-linux-androideabi-ar"
+  }
+  tool_path {
+    name: "cpp"
+    path: "arm/bin/arm-linux-androideabi-cpp"
+  }
+  tool_path {
+    name: "gcov"
+    path: "arm/bin/arm-linux-androideabi-gcov"
+  }
+  tool_path {
+    name: "ld"
+    path: "arm/bin/arm-linux-androideabi-ld"
+  }
+  tool_path {
+    name: "nm"
+    path: "arm/bin/arm-linux-androideabi-nm"
+  }
+  tool_path {
+    name: "objcopy"
+    path: "arm/bin/arm-linux-androideabi-objcopy"
+  }
+  tool_path {
+    name: "objdump"
+    path: "arm/bin/arm-linux-androideabi-objdump"
+  }
+  tool_path {
+    name: "strip"
+    path: "arm/bin/arm-linux-androideabi-strip"
+  }
+  tool_path {
+    name: "ld-bfd"
+    path: "arm/bin/arm-linux-androideabi-ld.bfd"
+  }
+  tool_path {
+    name: "ld-gold"
+    path: "arm/bin/arm-linux-androideabi-ld.gold"
+  }
+}
+
+toolchain {
+  toolchain_identifier: "x86"
+  host_system_name: "x86"
+  target_system_name: "x86-linux-android"
+
+  target_cpu: "x86"
+  target_libc: "local"
+  compiler: "gcc"
+  abi_version: "x86"
+  abi_libc_version: "r7"
+  tool_path {
+    name: "gcc"
+    path: "x86/bin/i686-linux-android-gcc"
+  }
+  tool_path {
+    name: "ar"
+    path: "x86/bin/i686-linux-android-ar"
+  }
+  tool_path {
+    name: "cpp"
+    path: "x86/bin/i686-linux-android-cpp"
+  }
+  tool_path {
+    name: "gcov"
+    path: "x86/bin/i686-linux-android-gcov"
+  }
+  tool_path {
+    name: "ld"
+    path: "x86/bin/i686-linux-android-ld"
+  }
+  tool_path {
+    name: "nm"
+    path: "x86/bin/i686-linux-android-nm"
+  }
+  tool_path {
+    name: "objcopy"
+    path: "x86/bin/i686-linux-android-objcopy"
+  }
+  tool_path {
+    name: "objdump"
+    path: "x86/bin/i686-linux-android-objdump"
+  }
+  tool_path {
+    name: "strip"
+    path: "x86/bin/i686-linux-android-strip"
+  }
+  tool_path {
+    name: "ld-bfd"
+    path: "x86/bin/i686-linux-android-ld.bfd"
+  }
+  tool_path {
+    name: "ld-gold"
+    path: "x86/bin/i686-linux-android-ld.gold"
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkSplitTransitionTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkSplitTransitionTest.java
new file mode 100644
index 0000000..f5f4395
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkSplitTransitionTest.java
@@ -0,0 +1,171 @@
+// Copyright 2016 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.rules.android;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
+import com.google.devtools.build.lib.packages.util.BazelMockAndroidSupport;
+import com.google.devtools.build.lib.syntax.Runtime;
+import java.util.List;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class AndroidSkylarkSplitTransitionTest extends BuildViewTestCase {
+
+  protected boolean keepGoing() {
+    return false;
+  }
+
+  private void writeAndroidSplitTransitionTestFiles() throws Exception  {
+    scratch.file(
+        "test/skylark/my_rule.bzl",
+        "def impl(ctx): ",
+        "  return struct(",
+        "    split_attr_deps = ctx.split_attr.deps,",
+        "    split_attr_dep = ctx.split_attr.dep,",
+        "    k8_deps = ctx.split_attr.deps.get('k8', None),",
+        "    attr_deps = ctx.attr.deps,",
+        "    attr_dep = ctx.attr.dep)",
+        "my_rule = rule(",
+        "  implementation = impl,",
+        "  attrs = {",
+        "    'deps': attr.label_list(cfg = android_common.multi_cpu_configuration),",
+        "    'dep':  attr.label(cfg = android_common.multi_cpu_configuration),",
+        "  })");
+
+    scratch.file(
+        "test/skylark/BUILD",
+        "load('/test/skylark/my_rule', 'my_rule')",
+        "my_rule(name = 'test', deps = [':main1', ':main2'], dep = ':main1')",
+        "cc_binary(name = 'main1', srcs = ['main1.c'])",
+        "cc_binary(name = 'main2', srcs = ['main2.c'])");
+  }
+
+  @Test
+  public void testAndroidSplitTransition() throws Exception {
+    writeAndroidSplitTransitionTestFiles();
+
+    useConfiguration("--fat_apk_cpu=k8,armeabi-v7a");
+    ConfiguredTarget target = getConfiguredTarget("//test/skylark:test");
+
+    // Check that ctx.split_attr.deps has this structure:
+    // {
+    //   "k8": [ConfiguredTarget],
+    //   "armeabi-v7a": [ConfiguredTarget],
+    // }
+    @SuppressWarnings("unchecked")
+    Map<String, List<ConfiguredTarget>> splitDeps =
+        (Map<String, List<ConfiguredTarget>>) target.get("split_attr_deps");
+    assertThat(splitDeps).containsKey("k8");
+    assertThat(splitDeps).containsKey("armeabi-v7a");
+    assertThat(splitDeps.get("k8")).hasSize(2);
+    assertThat(splitDeps.get("armeabi-v7a")).hasSize(2);
+    assertThat(splitDeps.get("k8").get(0).getConfiguration().getCpu()).isEqualTo("k8");
+    assertThat(splitDeps.get("k8").get(1).getConfiguration().getCpu()).isEqualTo("k8");
+    assertThat(splitDeps.get("armeabi-v7a").get(0).getConfiguration().getCpu())
+        .isEqualTo("armeabi-v7a");
+    assertThat(splitDeps.get("armeabi-v7a").get(1).getConfiguration().getCpu())
+        .isEqualTo("armeabi-v7a");
+
+    // Check that ctx.split_attr.dep has this structure (that is, that the values are not lists):
+    // {
+    //   "k8": ConfiguredTarget,
+    //   "armeabi-v7a": ConfiguredTarget,
+    // }
+    @SuppressWarnings("unchecked")
+    Map<String, ConfiguredTarget> splitDep =
+        (Map<String, ConfiguredTarget>) target.get("split_attr_dep");
+    assertThat(splitDep).containsKey("k8");
+    assertThat(splitDep).containsKey("armeabi-v7a");
+    assertThat(splitDep.get("k8").getConfiguration().getCpu()).isEqualTo("k8");
+    assertThat(splitDep.get("armeabi-v7a").getConfiguration().getCpu()).isEqualTo("armeabi-v7a");
+
+    // The regular ctx.attr.deps should be a single list with all the branches of the split merged
+    // together (i.e. for aspects).
+    @SuppressWarnings("unchecked")
+    List<ConfiguredTarget> attrDeps = (List<ConfiguredTarget>) target.get("attr_deps");
+    assertThat(attrDeps).hasSize(4);
+    ListMultimap<String, Object> attrDepsMap = ArrayListMultimap.create();
+    for (ConfiguredTarget ct : attrDeps) {
+      attrDepsMap.put(ct.getConfiguration().getCpu(), target);
+    }
+    assertThat(attrDepsMap.get("k8")).hasSize(2);
+    assertThat(attrDepsMap.get("armeabi-v7a")).hasSize(2);
+
+    // Check that even though my_rule.dep is defined as a single label, ctx.attr.dep is still a list
+    // with multiple ConfiguredTarget objects because of the two different CPUs. 
+    @SuppressWarnings("unchecked")
+    List<ConfiguredTarget> attrDep = (List<ConfiguredTarget>) target.get("attr_dep");
+    assertThat(attrDep).hasSize(2);
+    ListMultimap<String, Object> attrDepMap = ArrayListMultimap.create();
+    for (ConfiguredTarget ct : attrDep) {
+      attrDepMap.put(ct.getConfiguration().getCpu(), target);
+    }
+    assertThat(attrDepMap.get("k8")).hasSize(1);
+    assertThat(attrDepMap.get("armeabi-v7a")).hasSize(1);
+
+    // Check that the deps were correctly accessed from within Skylark.
+    @SuppressWarnings("unchecked")
+    List<ConfiguredTarget> k8Deps = (List<ConfiguredTarget>) target.get("k8_deps");
+    assertThat(k8Deps).hasSize(2);
+    assertThat(k8Deps.get(0).getConfiguration().getCpu()).isEqualTo("k8");
+    assertThat(k8Deps.get(1).getConfiguration().getCpu()).isEqualTo("k8");
+  }
+
+  @Test
+  public void testAndroidSplitTransitionWithAndroidCpu() throws Exception {
+    writeAndroidSplitTransitionTestFiles();
+    BazelMockAndroidSupport.setupNdk(mockToolsConfig);
+
+    // --android_cpu with --android_crosstool_top also triggers the split transition.
+    useConfiguration(
+        "--android_cpu=armeabi-v7a", "--android_crosstool_top=//android/crosstool:everything");
+    ConfiguredTarget target = getConfiguredTarget("//test/skylark:test");
+
+    @SuppressWarnings("unchecked")
+    Map<Object, List<ConfiguredTarget>> splitDeps =
+        (Map<Object, List<ConfiguredTarget>>) target.get("split_attr_deps");
+
+    String cpu = "armeabi-v7a";
+    assertThat(splitDeps.get(cpu)).hasSize(2);
+    assertThat(splitDeps.get(cpu).get(0).getConfiguration().getCpu()).isEqualTo(cpu);
+    assertThat(splitDeps.get(cpu).get(1).getConfiguration().getCpu()).isEqualTo(cpu);
+  }
+
+  @Test
+  public void testAndroidSplitTransitionNoTransition() throws Exception {
+    writeAndroidSplitTransitionTestFiles();
+
+    useConfiguration("--fat_apk_cpu=", "--android_crosstool_top=");
+    ConfiguredTarget target = getConfiguredTarget("//test/skylark:test");
+
+    @SuppressWarnings("unchecked")
+    Map<Object, List<ConfiguredTarget>> splitDeps =
+        (Map<Object, List<ConfiguredTarget>>) target.get("split_attr_deps");
+
+    // Split transition isn't in effect, so the deps are compiled normally (i.e. using --cpu).
+    assertThat(splitDeps.get(Runtime.NONE)).hasSize(2);
+    assertThat(splitDeps.get(Runtime.NONE).get(0).getConfiguration().getCpu()).isEqualTo("k8");
+    assertThat(splitDeps.get(Runtime.NONE).get(1).getConfiguration().getCpu()).isEqualTo("k8");
+  }
+  
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/BUILD b/src/test/java/com/google/devtools/build/lib/rules/android/BUILD
new file mode 100644
index 0000000..460be99
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/BUILD
@@ -0,0 +1,18 @@
+filegroup(
+    name = "srcs",
+    srcs = glob(["**"]),
+    visibility = ["//src/test/java/com/google/devtools/build/lib:__pkg__"],
+)
+
+java_test(
+    name = "AndroidSkylarkSplitTransitionTest",
+    srcs = ["AndroidSkylarkSplitTransitionTest.java"],
+    deps = [
+        "//src/main/java/com/google/devtools/build/lib:build-base",
+        "//src/main/java/com/google/devtools/build/lib:syntax",
+        "//src/test/java/com/google/devtools/build/lib:analysis_testutil",
+        "//src/test/java/com/google/devtools/build/lib:packages_testutil",
+        "//third_party:guava",
+        "//third_party:truth",
+    ],
+)
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 a5fa37d..85c00a3 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/skylark/BUILD
@@ -59,6 +59,7 @@
         "//src/test/java/com/google/devtools/build/lib:actions_testutil",
         "//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:packages_testutil",
         "//src/test/java/com/google/devtools/build/lib:test_runner",
         "//src/test/java/com/google/devtools/build/lib:testutil",
         "//third_party:guava",