Make ios_multi_cpus, macos_cpus, watchos_cpus and tvos_cpus flags additive, so that --ios_multi_cpus=arm64 --ios_multi_cpus=armv7 and --ios_multi_cpus=armv7,arm64 are semantically equivalent.

RELNOTES: The --ios_multi_cpus, --watchos_cpus, --macos_cpus and tvos_cpus are now additive. This means that you can now split the --ios_multi_cpus=arm64,armv7 into --ios_multi_cpus=arm64 and --ios_multi_cpus=armv7.
PiperOrigin-RevId: 241996129
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 81d7f23..f21a639 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
@@ -258,45 +258,45 @@
   public ConfigurationDistinguisher configurationDistinguisher;
 
   @Option(
-    name = "ios_multi_cpus",
-    converter = CommaSeparatedOptionListConverter.class,
-    defaultValue = "",
-    documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
-    effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
-    help =
-        "Comma-separated list of architectures to build an ios_application with. The result "
-            + "is a universal binary containing all specified architectures."
-  )
+      name = "ios_multi_cpus",
+      allowMultiple = true,
+      converter = CommaSeparatedOptionListConverter.class,
+      defaultValue = "unused",
+      documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
+      effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
+      help =
+          "Comma-separated list of architectures to build an ios_application with. The result "
+              + "is a universal binary containing all specified architectures.")
   public List<String> iosMultiCpus;
 
   @Option(
-    name = "watchos_cpus",
-    converter = CommaSeparatedOptionListConverter.class,
-    defaultValue = DEFAULT_WATCHOS_CPU,
-    documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
-    effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
-    help = "Comma-separated list of architectures for which to build Apple watchOS binaries."
-  )
+      name = "watchos_cpus",
+      allowMultiple = true,
+      converter = CommaSeparatedOptionListConverter.class,
+      defaultValue = "unused",
+      documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
+      effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
+      help = "Comma-separated list of architectures for which to build Apple watchOS binaries.")
   public List<String> watchosCpus;
 
   @Option(
-    name = "tvos_cpus",
-    converter = CommaSeparatedOptionListConverter.class,
-    defaultValue = DEFAULT_TVOS_CPU,
-    documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
-    effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
-    help = "Comma-separated list of architectures for which to build Apple tvOS binaries."
-  )
+      name = "tvos_cpus",
+      allowMultiple = true,
+      converter = CommaSeparatedOptionListConverter.class,
+      defaultValue = "unused",
+      documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
+      effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
+      help = "Comma-separated list of architectures for which to build Apple tvOS binaries.")
   public List<String> tvosCpus;
 
   @Option(
-    name = "macos_cpus",
-    converter = CommaSeparatedOptionListConverter.class,
-    defaultValue = DEFAULT_MACOS_CPU,
-    documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
-    effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
-    help = "Comma-separated list of architectures for which to build Apple macOS binaries."
-  )
+      name = "macos_cpus",
+      allowMultiple = true,
+      converter = CommaSeparatedOptionListConverter.class,
+      defaultValue = "unused",
+      documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
+      effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE, OptionEffectTag.LOADING_AND_ANALYSIS},
+      help = "Comma-separated list of architectures for which to build Apple macOS binaries.")
   public List<String> macosCpus;
 
   @Option(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java
index 37588a7..938bc61 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleCrosstoolTransition.java
@@ -115,10 +115,19 @@
           return AppleConfiguration.iosCpuFromCpu(configOptions.cpu);
         }
       case WATCHOS:
+        if (appleOptions.watchosCpus.isEmpty()) {
+          return AppleCommandLineOptions.DEFAULT_WATCHOS_CPU;
+        }
         return appleOptions.watchosCpus.get(0);
       case TVOS:
+        if (appleOptions.tvosCpus.isEmpty()) {
+          return AppleCommandLineOptions.DEFAULT_TVOS_CPU;
+        }
         return appleOptions.tvosCpus.get(0);
       case MACOS:
+        if (appleOptions.macosCpus.isEmpty()) {
+          return AppleCommandLineOptions.DEFAULT_MACOS_CPU;
+        }
         return appleOptions.macosCpus.get(0);
       default:
         throw new IllegalArgumentException(
diff --git a/src/test/shell/bazel/apple/bazel_apple_test.sh b/src/test/shell/bazel/apple/bazel_apple_test.sh
index 2835470..f35ad88 100755
--- a/src/test/shell/bazel/apple/bazel_apple_test.sh
+++ b/src/test/shell/bazel/apple/bazel_apple_test.sh
@@ -79,6 +79,49 @@
     || fail "expected output binary to contain 2 architectures"
 }
 
+function test_additive_cpus_flag() {
+  mkdir -p package
+  cat > package/BUILD <<EOF
+objc_library(
+    name = "lib_a",
+    srcs = ["a.m"],
+)
+objc_library(
+    name = "lib_b",
+    srcs = ["b.m"],
+)
+apple_binary(
+    name = "main_binary",
+    deps = [":lib_a", ":lib_b"],
+    platform_type = "ios",
+    minimum_os_version = "10.0",
+)
+genrule(
+  name = "lipo_run",
+  srcs = [":main_binary_lipobin"],
+  outs = ["lipo_out"],
+  cmd =
+      "set -e && " +
+      "lipo -info \$(location :main_binary_lipobin) > \$(@)",
+  tags = ["requires-darwin"],
+)
+EOF
+  touch package/a.m
+  cat > package/b.m <<EOF
+int main() {
+  return 0;
+}
+EOF
+
+  bazel build --verbose_failures --xcode_version=$XCODE_VERSION \
+      //package:lipo_out \
+      --ios_multi_cpus=i386 --ios_multi_cpus=x86_64 \
+      || fail "should build apple_binary and obtain info via lipo"
+
+  cat bazel-genfiles/package/lipo_out | grep "i386 x86_64" \
+    || fail "expected output binary to contain 2 architectures"
+}
+
 function test_host_xcodes() {
   XCODE_VERSION=$(env -i xcodebuild -version | grep "Xcode" \
       | sed -E "s/Xcode (([0-9]|.)+).*/\1/")