Support for platform_type="watchos" on apple_binary.

This builds all dependencies linked against watch SDKs instead of iOS SDKs, and builds for the architectures specified in --watchos_multi_cpus

RELNOTES: apple_binary supports a new platform_type attribute, which, if set to "watchos", will build dependencies for Apple's watchOS2.

--
MOS_MIGRATED_REVID=124980029
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 3977caf..9c0c4742 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
@@ -459,7 +459,8 @@
    * <p>If the name of the attribute starts with <code>$</code>
    * it is replaced with a string <code>(an implicit dependency)</code>.
    */
-  public void throwWithAttributeError(String attrName, String message) throws RuleErrorException {
+  public RuleErrorException throwWithAttributeError(String attrName, String message)
+      throws RuleErrorException {
     reporter.attributeError(attrName, message);
     throw new RuleErrorException();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
index a691d9bb..379068d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleCommandLineOptions.java
@@ -87,6 +87,12 @@
   @VisibleForTesting public static final String DEFAULT_WATCHOS_SDK_VERSION = "2.0";
   @VisibleForTesting public static final String DEFAULT_MACOSX_SDK_VERSION = "10.10";
   @VisibleForTesting public static final String DEFAULT_APPLETVOS_SDK_VERSION = "1.0";
+  @VisibleForTesting static final String DEFAULT_IOS_CPU = "x86_64";
+
+  /**
+   * The default watchos CPU value.
+   */
+  public static final String DEFAULT_WATCHOS_CPU = "i386";
 
   @Option(name = "ios_cpu",
       defaultValue = DEFAULT_IOS_CPU,
@@ -131,7 +137,12 @@
           + "is a universal binary containing all specified architectures.")
   public List<String> iosMultiCpus;
 
-  @VisibleForTesting static final String DEFAULT_IOS_CPU = "x86_64";
+  @Option(name = "watchos_cpus",
+      converter = CommaSeparatedOptionListConverter.class,
+      defaultValue = DEFAULT_WATCHOS_CPU,
+      category = "flags",
+      help = "Comma-separated list of architectures for which to build apple watchos binaries.")
+  public List<String> watchosCpus;
 
   @Option(name = "default_ios_provisioning_profile",
       defaultValue = "",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
index 3b9745f..ebc8c98 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleConfiguration.java
@@ -76,6 +76,7 @@
   private final ConfigurationDistinguisher configurationDistinguisher;
   private final Optional<DottedVersion> xcodeVersion;
   private final ImmutableList<String> iosMultiCpus;
+  private final ImmutableList<String> watchosCpus;
   private final AppleBitcodeMode bitcodeMode;
   private final Label xcodeConfigLabel;
   @Nullable private final Label defaultProvisioningProfileLabel;
@@ -102,6 +103,9 @@
     this.configurationDistinguisher = appleOptions.configurationDistinguisher;
     this.iosMultiCpus = ImmutableList.copyOf(
         Preconditions.checkNotNull(appleOptions.iosMultiCpus, "iosMultiCpus"));
+    this.watchosCpus = (appleOptions.watchosCpus == null || appleOptions.watchosCpus.isEmpty())
+        ? ImmutableList.of(AppleCommandLineOptions.DEFAULT_WATCHOS_CPU)
+        : ImmutableList.copyOf(appleOptions.watchosCpus);
     this.bitcodeMode = appleOptions.appleBitcodeMode;
     this.xcodeConfigLabel =
         Preconditions.checkNotNull(appleOptions.xcodeVersionConfig, "xcodeConfigLabel");
@@ -201,11 +205,13 @@
   public Map<String, String> appleTargetPlatformEnv(Platform platform) {
     ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
 
-    // TODO(bazel-team): Handle non-ios platforms.
-    if (platform == Platform.IOS_DEVICE || platform == Platform.IOS_SIMULATOR) {
-      String sdkVersion = getSdkVersionForPlatform(platform).toString();
-      builder.put(AppleConfiguration.APPLE_SDK_VERSION_ENV_NAME, sdkVersion)
-          .put(AppleConfiguration.APPLE_SDK_PLATFORM_ENV_NAME, platform.getNameInPlist());
+    // TODO(cparsons): Avoid setting SDK version for macosx. Until SDK version is
+    // evaluated for the current configuration xcode version, this would break users who build
+    // cc_* rules without specifying both xcode_version and macosx_sdk_version build options.
+    if (platform != Platform.MACOS_X) {
+        String sdkVersion = getSdkVersionForPlatform(platform).toString();
+        builder.put(AppleConfiguration.APPLE_SDK_VERSION_ENV_NAME, sdkVersion)
+            .put(AppleConfiguration.APPLE_SDK_PLATFORM_ENV_NAME, platform.getNameInPlist());
     }
     return builder.build();
   }
@@ -246,7 +252,9 @@
         } else {
           return getIosCpu();
         }
-      // TODO(cparsons): Support platform types other than iOS.
+      case WATCHOS:
+        return watchosCpus.get(0);
+      // TODO(cparsons): Handle all platform types.
       default: 
         throw new IllegalArgumentException("Unhandled platform type " + applePlatformType);
     }
@@ -286,7 +294,8 @@
         } else {
           return getIosMultiCpus();
         }
-      // TODO(cparsons): Support other platform types.
+      case WATCHOS:
+        return watchosCpus;
       default: 
         throw new IllegalArgumentException("Unhandled platform type " + platformType);
     }
@@ -313,12 +322,24 @@
   // TODO(bazel-team): This should support returning multiple platforms.
   public Platform getMultiArchPlatform(PlatformType platformType) {
     List<String> architectures = getMultiArchitectures(platformType);
-    for (String arch : architectures) {
-      if (Platform.forTarget(PlatformType.IOS, arch) == Platform.IOS_DEVICE) {
-        return Platform.IOS_DEVICE;
-      }
+    switch (platformType) {
+      case IOS:
+        for (String arch : architectures) {
+          if (Platform.forTarget(PlatformType.IOS, arch) == Platform.IOS_DEVICE) {
+            return Platform.IOS_DEVICE;
+          }
+        }
+        return Platform.IOS_SIMULATOR;
+      case WATCHOS:
+        for (String arch : architectures) {
+          if (Platform.forTarget(PlatformType.WATCHOS, arch) == Platform.WATCHOS_DEVICE) {
+            return Platform.WATCHOS_DEVICE;
+          }
+        }
+        return Platform.WATCHOS_SIMULATOR;
+      default:
+        throw new IllegalArgumentException("Unsupported platform type " + platformType);
     }
-    return Platform.IOS_SIMULATOR;
   }
 
   /**
@@ -498,7 +519,9 @@
     FRAMEWORK,
     /** Split transition distinguisher for {@code apple_watch1_extension} rule. */
     WATCH_OS1_EXTENSION,
-    /** Split transition distinguisher for {@code apple_binary} rule. */
-    APPLEBIN_IOS
+    /** Distinguisher for {@code apple_binary} rule with "ios" platform_type. */
+    APPLEBIN_IOS,
+    /** Distinguisher for {@code apple_binary} rule with "watchos" platform_type. */
+    APPLEBIN_WATCHOS,
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleToolchain.java
index 097f24f..15e0622 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/AppleToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/AppleToolchain.java
@@ -140,6 +140,10 @@
       case MACOS_X:
         relativePath = DEVELOPER_FRAMEWORK_PATH;
         break;
+      case WATCHOS_DEVICE:
+      case WATCHOS_SIMULATOR:
+        relativePath = SYSTEM_FRAMEWORK_PATH;
+        break;
       default:
         throw new IllegalArgumentException("Unhandled platform " + targetPlatform);
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/Platform.java b/src/main/java/com/google/devtools/build/lib/rules/apple/Platform.java
index 21c1755..7a8b1d1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/Platform.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/Platform.java
@@ -29,25 +29,39 @@
  */
 @SkylarkModule(name = "platform", doc = "Distinguishes between various apple platforms.")
 public enum Platform {
-  IOS_DEVICE("iPhoneOS"),
-  IOS_SIMULATOR("iPhoneSimulator"),
-  MACOS_X("MacOSX"),
-  TVOS_DEVICE("AppleTVOS"),
-  TVOS_SIMULATOR("AppleTVSimulator"),
-  WATCHOS_DEVICE("WatchOS"),
-  WATCHOS_SIMULATOR("WatchSimulator");
+
+  IOS_DEVICE("iPhoneOS", PlatformType.IOS),
+  IOS_SIMULATOR("iPhoneSimulator", PlatformType.IOS),
+  MACOS_X("MacOSX", PlatformType.MACOSX),
+  TVOS_DEVICE("AppleTVOS", PlatformType.TVOS),
+  TVOS_SIMULATOR("AppleTVSimulator", PlatformType.TVOS),
+  WATCHOS_DEVICE("WatchOS", PlatformType.WATCHOS),
+  WATCHOS_SIMULATOR("WatchSimulator", PlatformType.WATCHOS);
 
   private static final Set<String> IOS_SIMULATOR_TARGET_CPUS =
       ImmutableSet.of("ios_x86_64", "ios_i386");
+  private static final Set<String> WATCHOS_SIMULATOR_TARGET_CPUS =
+      ImmutableSet.of("watchos_i386");
+  private static final Set<String> WATCHOS_DEVICE_TARGET_CPUS =
+      ImmutableSet.of("watchos_armv7k");
   private static final Set<String> IOS_DEVICE_TARGET_CPUS =
       ImmutableSet.of("ios_armv6", "ios_arm64", "ios_armv7", "ios_armv7s");
   private static final Set<String> MACOSX_TARGET_CPUS =
       ImmutableSet.of("darwin_x86_64");
 
   private final String nameInPlist;
+  private final PlatformType platformType;
 
-  Platform(String nameInPlist) {
+  Platform(String nameInPlist, PlatformType platformType) {
     this.nameInPlist = Preconditions.checkNotNull(nameInPlist);
+    this.platformType = platformType;
+  }
+
+  /**
+   * Returns the platform type of this platform.
+   */
+  public PlatformType getType() {
+    return platformType;
   }
 
   /**
@@ -75,6 +89,10 @@
       return IOS_SIMULATOR;
     } else if (IOS_DEVICE_TARGET_CPUS.contains(targetCpu)) {
       return IOS_DEVICE;
+    } else if (WATCHOS_SIMULATOR_TARGET_CPUS.contains(targetCpu)) {
+      return WATCHOS_SIMULATOR;
+    } else if (WATCHOS_DEVICE_TARGET_CPUS.contains(targetCpu)) {
+      return WATCHOS_DEVICE;
     } else if (MACOSX_TARGET_CPUS.contains(targetCpu)) {
       return MACOS_X;
     } else {
@@ -131,5 +149,19 @@
     public String toString() {
       return name().toLowerCase();
     }
+    
+    /**
+     * Returns the {@link PlatformType} with given name (case insensitive).
+     * 
+     * @throws IllegalArgumentException if the name does not match a valid platform type.
+     */
+    public static PlatformType fromString(String name) {
+      for (PlatformType platformType : PlatformType.values()) {
+        if (name.equalsIgnoreCase(platformType.toString())) {
+          return platformType;
+        }
+      }
+      throw new IllegalArgumentException(String.format("Unsupported platform type \"%s\"", name));
+    }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
index 325c7bf..017d245 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
@@ -14,10 +14,14 @@
 
 package com.google.devtools.build.lib.rules.objc;
 
+import static com.google.devtools.build.lib.syntax.Type.STRING;
+
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
@@ -29,6 +33,7 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.packages.Attribute.SplitTransition;
 import com.google.devtools.build.lib.packages.Attribute.SplitTransitionProvider;
+import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions;
@@ -59,9 +64,17 @@
   static final String REQUIRES_AT_LEAST_ONE_SOURCE_FILE =
       "At least one source file is required (srcs, non_arc_srcs, or precompiled_srcs).";
 
+  @VisibleForTesting
+  static final String UNSUPPORTED_PLATFORM_TYPE_ERROR_FORMAT =
+      "Unsupported platform type \"%s\"";
+
+  private static final ImmutableSet<PlatformType> SUPPORTED_APPLE_BINARY_PLATFORM_TYPES =
+      ImmutableSet.of(PlatformType.IOS, PlatformType.WATCHOS);
+
   @Override
   public final ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException {
+    PlatformType platformType = getPlatformType(ruleContext);
     ImmutableListMultimap<BuildConfiguration, ObjcProvider> configurationToNonPropagatedObjcMap =
         ruleContext.getPrerequisitesByConfiguration("non_propagated_deps", Mode.SPLIT,
             ObjcProvider.class);
@@ -143,11 +156,11 @@
         .registerCombineArchitecturesAction(
             binariesToLipo.build(),
             ruleIntermediateArtifacts.combinedArchitectureBinary(),
-            appleConfiguration.getMultiArchPlatform(PlatformType.IOS))
+            appleConfiguration.getMultiArchPlatform(platformType))
         .registerCombineArchitecturesAction(
             archivesToLipo.build(),
             ruleContext.getImplicitOutputArtifact(AppleBinaryRule.LIPO_ARCHIVE),
-            appleConfiguration.getMultiArchPlatform(PlatformType.IOS));
+            appleConfiguration.getMultiArchPlatform(platformType));
 
     RuleConfiguredTargetBuilder targetBuilder =
         ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build());
@@ -205,22 +218,59 @@
     return configToProvider.keySet();
   }
 
+  private static PlatformType getPlatformType(RuleContext ruleContext) throws RuleErrorException {
+    try {
+      return getPlatformType(
+          ruleContext.attributes().get(AppleBinaryRule.PLATFORM_TYPE_ATTR_NAME, STRING));
+    } catch (IllegalArgumentException exception) {
+      throw ruleContext.throwWithAttributeError(AppleBinaryRule.PLATFORM_TYPE_ATTR_NAME,
+          String.format(UNSUPPORTED_PLATFORM_TYPE_ERROR_FORMAT,
+              ruleContext.attributes().get(AppleBinaryRule.PLATFORM_TYPE_ATTR_NAME, STRING)));
+    }
+  }
+
+  private static PlatformType getPlatformType(String platformTypeString) {
+    PlatformType platformType = PlatformType.fromString(platformTypeString);
+
+    if (!SUPPORTED_APPLE_BINARY_PLATFORM_TYPES.contains(platformType)) {
+      throw new IllegalArgumentException(
+          String.format(UNSUPPORTED_PLATFORM_TYPE_ERROR_FORMAT, platformTypeString));
+    } else {
+      return platformType;
+    }
+  }
+
   /**
    * {@link SplitTransitionProvider} implementation for the apple binary rule.
    */
   public static class AppleBinaryTransitionProvider implements SplitTransitionProvider {
 
-    private static final IosMultiCpusTransition IOS_MULTI_CPUS_SPLIT_TRANSITION =
-        new IosMultiCpusTransition();
+    private static final ImmutableMap<PlatformType, AppleBinaryTransition>
+        SPLIT_TRANSITIONS_BY_TYPE = ImmutableMap.<PlatformType, AppleBinaryTransition>builder()
+            .put(PlatformType.IOS, new AppleBinaryTransition(PlatformType.IOS))
+            .put(PlatformType.WATCHOS, new AppleBinaryTransition(PlatformType.WATCHOS))
+            .build();
 
     @Override
     public SplitTransition<?> apply(Rule fromRule) {
-      // TODO(cparsons): Support different split transitions based on rule attribute.
-      return IOS_MULTI_CPUS_SPLIT_TRANSITION;
+      String platformTypeString = NonconfigurableAttributeMapper.of(fromRule)
+          .get(AppleBinaryRule.PLATFORM_TYPE_ATTR_NAME, STRING);
+      PlatformType platformType;
+      try {
+        platformType = getPlatformType(platformTypeString);
+      } catch (IllegalArgumentException exception) {
+        // There's no opportunity to propagate exception information up cleanly at the transition
+        // provider level. This will later be registered as a rule error during the initialization
+        // of the apple_binary target.
+        platformType = PlatformType.IOS;
+      }
+
+      return SPLIT_TRANSITIONS_BY_TYPE.get(platformType);
     }
 
     public List<SplitTransition<BuildOptions>> getPotentialSplitTransitions() {
-      return ImmutableList.<SplitTransition<BuildOptions>>of(IOS_MULTI_CPUS_SPLIT_TRANSITION);
+      return ImmutableList.<SplitTransition<BuildOptions>>copyOf(
+          SPLIT_TRANSITIONS_BY_TYPE.values());
     }
   }
 
@@ -228,29 +278,54 @@
    * Transition that results in one configured target per architecture specified in {@code
    * --ios_multi_cpus}.
    */
-  protected static class IosMultiCpusTransition implements SplitTransition<BuildOptions> {
+  protected static class AppleBinaryTransition implements SplitTransition<BuildOptions> {
+
+    private final PlatformType platformType;
+
+    public AppleBinaryTransition(PlatformType platformType) {
+      this.platformType = platformType;
+    }
 
     @Override
     public final List<BuildOptions> split(BuildOptions buildOptions) {
-      List<String> iosMultiCpus = buildOptions.get(AppleCommandLineOptions.class).iosMultiCpus;
+      List<String> cpus;
+      ConfigurationDistinguisher configurationDistinguisher;
+      switch (platformType) {
+        case IOS:
+          cpus = buildOptions.get(AppleCommandLineOptions.class).iosMultiCpus;
+          configurationDistinguisher = ConfigurationDistinguisher.APPLEBIN_IOS;
+          break;
+        case WATCHOS:
+          cpus = buildOptions.get(AppleCommandLineOptions.class).watchosCpus;
+          if (cpus.isEmpty()) {
+            cpus = ImmutableList.of(AppleCommandLineOptions.DEFAULT_WATCHOS_CPU);
+          }
+          configurationDistinguisher = ConfigurationDistinguisher.APPLEBIN_WATCHOS;
+          break;
+        default:
+          throw new IllegalArgumentException("Unsupported platform type " + platformType);
+      }
 
       ImmutableList.Builder<BuildOptions> splitBuildOptions = ImmutableList.builder();
-      for (String iosCpu : iosMultiCpus) {
+      for (String cpu : cpus) {
         BuildOptions splitOptions = buildOptions.clone();
 
-        splitOptions.get(AppleCommandLineOptions.class).iosMultiCpus = ImmutableList.of();
-        splitOptions.get(AppleCommandLineOptions.class).applePlatformType = PlatformType.IOS;
-        splitOptions.get(AppleCommandLineOptions.class).appleSplitCpu = iosCpu;
-        splitOptions.get(AppleCommandLineOptions.class).iosCpu = iosCpu;
+        splitOptions.get(AppleCommandLineOptions.class).applePlatformType = platformType;
+        splitOptions.get(AppleCommandLineOptions.class).appleSplitCpu = cpu;
+        // Set for backwards compatibility with rules that depend on this flag, even when
+        // ios is not the platform type.
+        // TODO(b/28958783): Clean this up.
+        splitOptions.get(AppleCommandLineOptions.class).iosCpu = cpu;
         if (splitOptions.get(ObjcCommandLineOptions.class).enableCcDeps) {
           // Only set the (CC-compilation) CPU for dependencies if explicitly required by the user.
           // This helps users of the iOS rules who do not depend on CC rules as these CPU values
           // require additional flags to work (e.g. a custom crosstool) which now only need to be
           // set if this feature is explicitly requested.
-          splitOptions.get(BuildConfiguration.Options.class).cpu = "ios_" + iosCpu;
+          splitOptions.get(BuildConfiguration.Options.class).cpu =
+              String.format("%s_%s", platformType, cpu);
         }
         splitOptions.get(AppleCommandLineOptions.class).configurationDistinguisher =
-            ConfigurationDistinguisher.APPLEBIN_IOS;
+            configurationDistinguisher;
         splitBuildOptions.add(splitOptions);
       }
       return splitBuildOptions.build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinaryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinaryRule.java
index 33920de..e69834d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinaryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinaryRule.java
@@ -18,6 +18,7 @@
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates;
 import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
+import static com.google.devtools.build.lib.syntax.Type.STRING;
 
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.RuleDefinition;
@@ -27,6 +28,7 @@
 import com.google.devtools.build.lib.packages.RuleClass;
 import com.google.devtools.build.lib.packages.RuleClass.Builder;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
+import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
 
 /**
  * Rule definition for apple_binary.
@@ -34,6 +36,12 @@
 public class AppleBinaryRule implements RuleDefinition {
 
   /**
+   * Attribute name for {@code apple_binary}'s apple platform type (for which all dependencies and
+   * sources of an {@code apple_binary} target will be built).
+   */
+  static final String PLATFORM_TYPE_ATTR_NAME = "platform_type";
+
+  /**
    * Template for the fat binary output (using Apple's "lipo" tool to combine binaries of
    * multiple architectures).
    */
@@ -60,6 +68,24 @@
         .add(attr(":cc_toolchain", LABEL)
             .cfg(AppleBinary.SPLIT_TRANSITION_PROVIDER)
             .value(ObjcRuleClasses.APPLE_TOOLCHAIN))
+        /* <!-- #BLAZE_RULE(apple_binary).ATTRIBUTE(platform_type) -->
+        The type of platform for which to create multi-architecture "fat" binaries in this rule.
+        For example, if <code>ios</code> is selected, then fat binaries will be created 
+        combining all architectures specified in <code>--ios_multi_cpus</code>.
+
+        Options are:
+        <ul>
+          <li>
+            <code>ios</code> (default): architectures gathered from <code>--ios_multi_cpus</code>.
+          </li>
+          <li>
+            <code>watchos</code>: architectures gathered from <code>--watchos_multi_cpus</code>
+          </li>
+        </ul>
+        <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
+        .add(attr(PLATFORM_TYPE_ATTR_NAME, STRING)
+            .value(PlatformType.IOS.toString())
+            .nonconfigurable("Determines the configuration transition on deps"))
         /*<!-- #BLAZE_RULE(apple_binary).IMPLICIT_OUTPUTS -->
         <ul>
          <li><code><var>name</var>_lipobin</code>: the 'lipo'ed potentially multi-architecture
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
index 995a65d..8e1fb4b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
@@ -64,7 +64,6 @@
 import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
 import com.google.devtools.build.lib.analysis.actions.CommandLine;
 import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
 import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
@@ -81,6 +80,7 @@
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
 import com.google.devtools.build.lib.rules.apple.AppleToolchain;
 import com.google.devtools.build.lib.rules.apple.Platform;
+import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
 import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
 import com.google.devtools.build.lib.rules.cpp.CppModuleMapAction;
 import com.google.devtools.build.lib.rules.cpp.LinkerInputs;
@@ -131,7 +131,7 @@
   // These are added by Xcode when building, because the simulator is built on OSX
   // frameworks so we aim compile to match the OSX objc runtime.
   @VisibleForTesting
-  static final ImmutableList<String> IOS_SIMULATOR_COMPILE_FLAGS =
+  static final ImmutableList<String> SIMULATOR_COMPILE_FLAGS =
       ImmutableList.of(
           "-fexceptions", "-fasm-blocks", "-fobjc-abi-version=2", "-fobjc-legacy-dispatch");
 
@@ -567,7 +567,7 @@
     // TODO(bazel-team): Remote private headers from inputs once they're added to the provider.
     ruleContext.registerAction(
         ObjcRuleClasses.spawnAppleEnvActionBuilder(
-                ruleContext, appleConfiguration.getSingleArchPlatform())
+                appleConfiguration, appleConfiguration.getSingleArchPlatform())
             .setMnemonic("ObjcCompile")
             .setExecutable(xcrunwrapper(ruleContext))
             .setCommandLine(commandLine.build())
@@ -696,7 +696,7 @@
 
     ruleContext.registerAction(
         ObjcRuleClasses.spawnAppleEnvActionBuilder(
-                ruleContext, appleConfiguration.getSingleArchPlatform())
+                appleConfiguration, appleConfiguration.getSingleArchPlatform())
             .setMnemonic("SwiftCompile")
             .setExecutable(xcrunwrapper(ruleContext))
             .setCommandLine(commandLine.build())
@@ -766,7 +766,7 @@
     commandLine.add(commonFrameworkFlags(objcProvider, appleConfiguration));
 
     ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder(
-            ruleContext, appleConfiguration.getSingleArchPlatform())
+            appleConfiguration, appleConfiguration.getSingleArchPlatform())
         .setMnemonic("SwiftModuleMerge")
         .setExecutable(xcrunwrapper(ruleContext))
         .setCommandLine(commandLine.build())
@@ -780,13 +780,12 @@
 
   private void registerArchiveActions(ImmutableList.Builder<Artifact> objFiles, Artifact archive) {
     for (Action action :
-        archiveActions(ruleContext, objFiles.build(), archive, intermediateArtifacts.objList())) {
+        archiveActions(objFiles.build(), archive, intermediateArtifacts.objList())) {
       ruleContext.registerAction(action);
     }
   }
 
   private Iterable<Action> archiveActions(
-      ActionConstructionContext context,
       Iterable<Artifact> objFiles,
       Artifact archive,
       Artifact objList) {
@@ -794,13 +793,13 @@
     ImmutableList.Builder<Action> actions = new ImmutableList.Builder<>();
 
     actions.add(new FileWriteAction(
-        context.getActionOwner(),
+        ruleContext.getActionOwner(),
         objList,
         Artifact.joinExecPaths("\n", objFiles),
         /*makeExecutable=*/ false));
 
     actions.add(ObjcRuleClasses.spawnAppleEnvActionBuilder(
-            ruleContext, appleConfiguration.getSingleArchPlatform())
+            appleConfiguration, appleConfiguration.getSingleArchPlatform())
         .setMnemonic("ObjcLink")
         .setExecutable(libtool(ruleContext))
         .setCommandLine(new CustomCommandLine.Builder()
@@ -813,7 +812,7 @@
         .addInputs(objFiles)
         .addInput(objList)
         .addOutput(archive)
-        .build(context));
+        .build(ruleContext));
 
     return actions.build();
   }
@@ -831,7 +830,7 @@
     ImmutableList<Artifact> objcLibraries = objcLibraries(objcProvider);
     ImmutableList<Artifact> ccLibraries = ccLibraries(objcProvider);
     ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder(
-            ruleContext, appleConfiguration.getSingleArchPlatform())
+            appleConfiguration, appleConfiguration.getSingleArchPlatform())
         .setMnemonic("ObjcLink")
         .setExecutable(libtool(ruleContext))
         .setCommandLine(new CustomCommandLine.Builder()
@@ -1033,7 +1032,7 @@
             linkmap);
     ruleContext.registerAction(
         ObjcRuleClasses.spawnAppleEnvActionBuilder(
-                ruleContext, appleConfiguration.getSingleArchPlatform())
+                appleConfiguration, appleConfiguration.getSingleArchPlatform())
             .setMnemonic("ObjcLink")
             .setShellCommand(ImmutableList.of("/bin/bash", "-c"))
             .setCommandLine(new SingleArgCommandLine(commandLine))
@@ -1067,7 +1066,7 @@
 
       ruleContext.registerAction(
           ObjcRuleClasses.spawnAppleEnvActionBuilder(
-                  ruleContext, appleConfiguration.getSingleArchPlatform())
+                  appleConfiguration, appleConfiguration.getSingleArchPlatform())
               .setMnemonic("ObjcBinarySymbolStrip")
               .setExecutable(xcrunwrapper(ruleContext))
               .setCommandLine(symbolStripCommandLine(stripArgs, binaryToLink, strippedBinary))
@@ -1337,7 +1336,7 @@
             commandLine,
             ParameterFile.ParameterFileType.UNQUOTED, ISO_8859_1));
         ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder(
-                ruleContext, appleConfiguration.getSingleArchPlatform())
+                appleConfiguration, appleConfiguration.getSingleArchPlatform())
             .setMnemonic("DummyPruner")
             .setExecutable(pruner)
             .addInput(dummyArchive)
@@ -1561,17 +1560,29 @@
   /**
    * Returns a list of clang flags used for all link and compile actions executed through clang.
    */
-  private static List<String> commonLinkAndCompileFlagsForClang(
+  private List<String> commonLinkAndCompileFlagsForClang(
       ObjcProvider provider, ObjcConfiguration objcConfiguration,
       AppleConfiguration appleConfiguration) {
     ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
     Platform platform = appleConfiguration.getSingleArchPlatform();
-    if (platform == Platform.IOS_SIMULATOR) {
-      builder.add("-mios-simulator-version-min=" + objcConfiguration.getMinimumOs());
-    } else {
-      builder.add("-miphoneos-version-min=" + objcConfiguration.getMinimumOs());
+    switch (platform) {
+      case IOS_SIMULATOR:
+        builder.add("-mios-simulator-version-min=" + objcConfiguration.getMinimumOs());
+        break;
+      case IOS_DEVICE:
+        builder.add("-miphoneos-version-min=" + objcConfiguration.getMinimumOs());
+        break;
+      case WATCHOS_SIMULATOR:
+        builder.add("-mwatchos-simulator-version-min="
+            + appleConfiguration.getSdkVersionForPlatform(platform));
+        break;
+      case WATCHOS_DEVICE:
+        builder.add("-mwatchos-version-min="
+            + appleConfiguration.getSdkVersionForPlatform(platform));
+        break;
+      default:
+        throw new IllegalArgumentException("Unhandled platform " + platform);
     }
-
     if (objcConfiguration.generateDebugSymbols() || objcConfiguration.generateDsym()) {
       builder.add("-g");
     }
@@ -1589,7 +1600,8 @@
    */
   static Iterable<String> commonFrameworkFlags(
       ObjcProvider provider, AppleConfiguration appleConfiguration) {
-    return Interspersing.beforeEach("-F", commonFrameworkNames(provider, appleConfiguration));
+    return Interspersing.beforeEach("-F",
+        commonFrameworkNames(provider, appleConfiguration));
   }
 
   /**
@@ -1599,10 +1611,13 @@
       ObjcProvider provider, AppleConfiguration appleConfiguration) {
     Platform platform = appleConfiguration.getSingleArchPlatform();
 
-    return new ImmutableList.Builder<String>()
-        .add(AppleToolchain.sdkFrameworkDir(platform, appleConfiguration))
+    ImmutableList.Builder<String> frameworkNames = new ImmutableList.Builder<String>()
+        .add(AppleToolchain.sdkFrameworkDir(platform, appleConfiguration));
+    if (platform.getType() == PlatformType.IOS) {
         // As of sdk8.1, XCTest is in a base Framework dir
-        .add(AppleToolchain.platformDeveloperFrameworkDir(appleConfiguration))
+      frameworkNames.add(AppleToolchain.platformDeveloperFrameworkDir(appleConfiguration));
+    }
+    return frameworkNames
         // Add custom (non-SDK) framework search paths. For each framework foo/bar.framework,
         // include "foo" as a search path.
         .addAll(PathFragment.safePathStrings(uniqueParentDirectories(provider.get(FRAMEWORK_DIR))))
@@ -1627,9 +1642,11 @@
       AppleConfiguration configuration) {
     switch (configuration.getSingleArchPlatform()) {
       case IOS_DEVICE:
+      case WATCHOS_DEVICE:
         return ImmutableList.of();
       case IOS_SIMULATOR:
-        return IOS_SIMULATOR_COMPILE_FLAGS;
+      case WATCHOS_SIMULATOR:
+        return SIMULATOR_COMPILE_FLAGS;
       default:
         throw new AssertionError();
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java
index e6a720b..8e8f309 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java
@@ -79,10 +79,10 @@
     }
 
     private void addFrameworkVariables(Builder builder) {
-       ValueSequence.Builder frameworkSequence = new ValueSequence.Builder();
+      ValueSequence.Builder frameworkSequence = new ValueSequence.Builder();
+      AppleConfiguration appleConfig = ruleContext.getFragment(AppleConfiguration.class);
       for (String framework :
-          CompilationSupport.commonFrameworkNames(
-              objcProvider, ruleContext.getFragment(AppleConfiguration.class))) {
+          CompilationSupport.commonFrameworkNames(objcProvider, appleConfig)) {
         frameworkSequence.addValue(framework);
       }
       builder.addSequence(FRAMEWORKS_VARIABLE_NAME, frameworkSequence.build());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
index 47cd993..a9edec7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java
@@ -201,8 +201,18 @@
   // retrieving it from the rule context.
   static SpawnAction.Builder spawnAppleEnvActionBuilder(RuleContext ruleContext,
       Platform targetPlatform) {
-    AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
-
+    return spawnAppleEnvActionBuilder(
+        ruleContext.getFragment(AppleConfiguration.class), targetPlatform);
+  }
+  
+  /**
+   * Creates a new spawn action builder with apple environment variables set that are typically
+   * needed by the apple toolchain. This should be used to start to build spawn actions that, in
+   * order to run, require both a darwin architecture and a collection of environment variables
+   * which contain information about the target and host architectures.
+   */
+  static SpawnAction.Builder spawnAppleEnvActionBuilder(AppleConfiguration appleConfiguration,
+      Platform targetPlatform) {
     ImmutableMap.Builder<String, String> envBuilder = ImmutableMap.<String, String>builder()
         .putAll(appleConfiguration.getTargetAppleEnvironment(targetPlatform))
         .putAll(appleConfiguration.getAppleHostSystemEnv());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeSupport.java
index 4719bfc..5e6b227 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/XcodeSupport.java
@@ -30,7 +30,6 @@
 import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration.ConfigurationDistinguisher;
-import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
 import com.google.devtools.build.lib.rules.objc.XcodeProvider.Builder;
 import com.google.devtools.build.lib.rules.objc.XcodeProvider.Project;
 import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos;
@@ -272,7 +271,8 @@
       this.project = project;
       this.pbxproj = pbxproj;
       this.workspaceRoot = objcConfiguration.getXcodeWorkspaceRoot();
-      this.appleCpus = appleConfiguration.getMultiArchitectures(PlatformType.IOS);
+      this.appleCpus = appleConfiguration.getMultiArchitectures(
+          appleConfiguration.getSingleArchPlatform().getType());
       this.minimumOs = objcConfiguration.getMinimumOs().toString();
       this.generateDebugSymbols =
           objcConfiguration.generateDebugSymbols() || objcConfiguration.generateDsym();