Add macOS universal binary (arm64 + x64) support#5
Closed
kdroidFilter wants to merge 10 commits intomainfrom
Closed
Add macOS universal binary (arm64 + x64) support#5kdroidFilter wants to merge 10 commits intomainfrom
kdroidFilter wants to merge 10 commits intomainfrom
Conversation
Build universal fat binaries by launching a separate Gradle process under Rosetta with an x64 JDK, then merging both distributables with lipo. Includes universal DMG/PKG packaging and notarization.
Allow producing x64-only installers from an Apple Silicon Mac without merging into a universal binary. The tasks run the full packaging pipeline in a subprocess with the x64 JDK.
The universal binary and x64-only packaging tasks are only useful on Apple Silicon (arm64) Macs. Guard their registration with a currentArch == Arm64 check so they are not created on x64 runners.
Setting x64JdkPath on the macOS block is sufficient to enable universal binary and x64-only tasks. No need for a separate UniversalBinarySettings class or an enabled flag.
When the environment variable is set, universal binary and x64-only tasks are enabled automatically without any build script configuration.
The JDK runtime's legal/ directory contains relative symlinks. The previous copyRecursively() call followed symlinks and failed when the target didn't resolve after being copied. Use java.nio.file.Files.walk with NOFOLLOW_LINKS to preserve symlinks as-is during both the base copy and the x64 merge walk.
xattr can fail on symlinks in the JDK runtime legal/ directory. Since clearing extended attributes is a best-effort cleanup step, log a warning instead of failing the build.
The .jpackage.xml file is jpackage internal metadata that encodes the jpackage version. When the host JDK (e.g. JBR-25) and the x64 JDK (e.g. Liberica 25.0.2) differ, jpackage rejects the file as "generated by another jpackage version". Skip it during both the base copy and the x64 merge so jpackage treats the universal app as a fresh app-image.
jpackage requires .jpackage.xml to be present in the app-image. Keep the arm64 version (generated by the host jpackage) during the base copy, and only skip it during the x64 merge to avoid version conflicts between different JDK distributions.
JBR-25 does not create .jpackage.xml in createDistributable, but requires it when using --app-image for packaging. The x64 build (Liberica) does create one but with a different version string. After the merge, if .jpackage.xml is missing from the universal app, copy it from the x64 build and patch the version attribute to match the host jpackage (via jpackage --version). This ensures the universal app is accepted by the host jpackage for DMG/PKG creation.
kdroidFilter
added a commit
that referenced
this pull request
Apr 19, 2026
X11 ICCCM compliance (#4/#5): - SetSelectionOwner now uses real server timestamp via PropertyNotify probe, not XCB_CURRENT_TIME (violates ICCCM §2.1). Added get_server_timestamp_locked() which fires a zero-byte ChangeProperty to trigger timestamp event. - TIMESTAMP replies now return g_own_ts (real value) instead of truncated 0. - Verified: xclip -o -t TIMESTAMP returns non-zero after our clipboard write. INCR cleanup (#3): - On INCR read timeout, delete property to unblock sender waiting for PropertyNotify=Delete (ICCCM compliant termination). Process lifecycle (#7): - Wayland: runCaptureBytes, runSilently, writeBytes now escalate to destroyForcibly() if SIGTERM doesn't terminate after 500ms grace. AccessBehavior mapping (#12): - Kotlin: explicit when() mapping (0→AlwaysAllow, 1→AskEveryTime, 2→AlwaysDeny) instead of ordinal/entries.getOrNull (fragile with future macOS versions). - ObjC: validate input 0..2 on set; return -1 if get() returns out-of-range. Documentation & robustness (#13, #1): - Clipboard.watch() doc: clarify poll interval is always honored; source of counter differs by backend (Mach IPC / XFixes / wl-paste). - Re-check isActive after slow availableFormats() to avoid emitting to cancelled flow. Added X11TimestampSmokeTest to verify real timestamps are used.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
universalBinary { enabled = true; x64JdkPath = "..." }DSL undermacOS {}to build fat macOS apps running natively on both Apple Silicon and IntellipomergeUniversalBinary,packageUniversalDmg/Pkg, andnotarizeUniversalDmg/Pkgtasks_universalsuffix instead of_arm64/_x64Files changed
UniversalBinarySettings.ktenabled,x64JdkPath)AbstractCreateDistributableX64Task.ktAbstractMergeUniversalBinaryTask.ktPlatformSettings.ktuniversalBinaryblock toJvmMacOSPlatformSettingsJvmApplicationContext.ktappTmpDirwith-x64in subprocess to isolate intermediatesconfigureJvmApplication.kt-x64),configureUniversalBinaryTasks()AbstractJPackageTask.ktuniversalBinaryFlagfor_universalfilename suffixREADME.mdTest plan
mergeUniversalBinaryproduces a universal.app(verified withlipo -info)packageUniversalDmgproduces_universal.dmgwith correct contentcodesign --verify --deep --strictpasses on the universal app