Add darwin_arm64 java_tools

Build a fat universal binary for java_tools_prebuilt on darwin

Work towards: https://github.com/bazelbuild/java_tools/issues/57 and https://github.com/bazelbuild/bazel/issues/13944

Closes #16960.

PiperOrigin-RevId: 512683379
Change-Id: Ie9db26c729a301fbb22f17dd15065861f3198f57
diff --git a/src/tools/singlejar/BUILD b/src/tools/singlejar/BUILD
index 625f006..e60b518 100644
--- a/src/tools/singlejar/BUILD
+++ b/src/tools/singlejar/BUILD
@@ -1,5 +1,6 @@
 load("@rules_java//java:defs.bzl", "java_library")
 load("//src:release_archive.bzl", "release_archive")
+load("//third_party/ijar:darwin_universal_binary.bzl", "darwin_universal_binary")
 
 # Description:
 #   singlejar C++ implementation.
@@ -64,7 +65,7 @@
 
 release_archive(
     name = "singlejar_deploy_zip",
-    srcs = [":singlejar_local"],
+    srcs = [":singlejar_local_binary_for_deploy"],
     package_dir = "java_tools/src/tools/singlejar",
     visibility = ["//src:__pkg__"],
 )
@@ -88,6 +89,20 @@
     ],
 )
 
+alias(
+    name = "singlejar_local_binary_for_deploy",
+    actual = select({
+        "//src/conditions:darwin": ":singlejar_local_darwin",
+        "//conditions:default": ":singlejar_local",
+    }),
+)
+
+darwin_universal_binary(
+    name = "singlejar_local_darwin",
+    binary = ":singlejar_local",
+    output_name = "singlejar_local",
+)
+
 cc_binary(
     name = "singlejar_local",
     srcs = [
diff --git a/third_party/ijar/BUILD b/third_party/ijar/BUILD
index 28f05bf..9a5fb22 100644
--- a/third_party/ijar/BUILD
+++ b/third_party/ijar/BUILD
@@ -1,3 +1,5 @@
+load(":darwin_universal_binary.bzl", "darwin_universal_binary")
+
 package(
     default_visibility = [
         "//src:__subpackages__",
@@ -76,6 +78,12 @@
     deps = [":zip"],
 )
 
+darwin_universal_binary(
+    name = "zipper_darwin",
+    binary = ":zipper",
+    output_name = "zipper",
+)
+
 cc_binary(
     name = "ijar",
     srcs = [
@@ -86,6 +94,12 @@
     deps = [":zip"],
 )
 
+darwin_universal_binary(
+    name = "ijar_darwin",
+    binary = ":ijar",
+    output_name = "ijar",
+)
+
 filegroup(
     name = "srcs",
     srcs = glob(["**"]) + ["//third_party/ijar/test:srcs"],
@@ -105,6 +119,7 @@
         "zlib_client.cc",
         "zlib_client.h",
         "BUILD",
+        "darwin_universal_binary.bzl",
     ] + select({
         "//src:windows": [
             "mapped_file_windows.cc",
@@ -137,10 +152,16 @@
 
 genrule(
     name = "ijar_deploy_zip",
-    srcs = [
-        ":ijar",
-        ":zipper",
-    ],
+    srcs = select({
+        "//src/conditions:darwin": [
+            ":ijar_darwin",
+            ":zipper_darwin",
+        ],
+        "//conditions:default": [
+            ":ijar",
+            ":zipper",
+        ],
+    }),
     outs = ["ijar_deploy.zip"],
     cmd = "$(location //src:zip_files) java_tools/ijar $@ $(SRCS)",
     tools = ["//src:zip_files"],
@@ -158,3 +179,8 @@
     tools = ["//src:zip_files"],
     visibility = ["//visibility:private"],
 )
+
+exports_files(
+    ["darwin_universal_binary.bzl"],
+    visibility = ["//src/tools/singlejar:__pkg__"],
+)
diff --git a/third_party/ijar/darwin_universal_binary.bzl b/third_party/ijar/darwin_universal_binary.bzl
new file mode 100644
index 0000000..ba7359e
--- /dev/null
+++ b/third_party/ijar/darwin_universal_binary.bzl
@@ -0,0 +1,61 @@
+""" Defines a rule to package multi-arch binaries for darwin in a single fat binary
+
+Uses the lipo tool as described here: https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary#Update-the-Architecture-List-of-Custom-Makefiles
+"""
+
+def _universal_split_transition_impl(_ctx, _attr):
+    return {
+        "x86_64": {
+            "//command_line_option:cpu": "darwin_x86_64",
+        },
+        "arm64": {
+            "//command_line_option:cpu": "darwin_arm64",
+        },
+    }
+
+_universal_split_transition = transition(
+    implementation = _universal_split_transition_impl,
+    inputs = [],
+    outputs = ["//command_line_option:cpu"],
+)
+
+def _impl(ctx):
+    binaries = [
+        attr.files.to_list()[0]
+        for attr in ctx.split_attr.binary.values()
+    ]
+    out = ctx.actions.declare_file(ctx.label.name + "/" + ctx.attr.output_name)
+    args = ctx.actions.args()
+    args.add("-create")
+    args.add_all(binaries)
+    args.add("-output", out)
+    apple_env = {}
+    xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]
+    apple_env.update(apple_common.apple_host_system_env(xcode_config))
+    apple_env.update(
+        apple_common.target_apple_env(
+            xcode_config,
+            ctx.fragments.apple.multi_arch_platform(apple_common.platform_type.macos),
+        ),
+    )
+    ctx.actions.run(
+        executable = "/usr/bin/lipo",
+        arguments = [args],
+        inputs = binaries,
+        outputs = [out],
+        execution_requirements = xcode_config.execution_info(),
+        env = apple_env,
+    )
+    return DefaultInfo(executable = out)
+
+darwin_universal_binary = rule(
+    implementation = _impl,
+    attrs = {
+        "output_name": attr.string(),
+        "binary": attr.label(cfg = _universal_split_transition),
+        "_xcode_config": attr.label(default = "@bazel_tools//tools/osx:current_xcode_config"),
+        "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"),
+    },
+    fragments = ["apple"],
+    exec_compatible_with = ["@platforms//os:macos"],
+)