Skip to content

Add macOS arm64 DMG installer build script#392

Open
Altair-Bueno wants to merge 1 commit into
intoolswetrust:masterfrom
Altair-Bueno:master
Open

Add macOS arm64 DMG installer build script#392
Altair-Bueno wants to merge 1 commit into
intoolswetrust:masterfrom
Altair-Bueno:master

Conversation

@Altair-Bueno
Copy link
Copy Markdown

Summary

Adds distribution/macos/build-macos-installers.sh, a jpackage-based build script that produces a macOS Apple Silicon DMG installer for JSignPdf. Mirrors the existing distribution/windows/build-windows-installers.ps1 pattern and reuses the shared distribution/jpackage/common-jvm-options.txt.

This is the first packaged macOS distribution for JSignPdf — until now Mac users had to run the shaded fat jar manually, which is broken on Apple Silicon (see #391).

Closes #391.

Motivation

The published jsignpdf-<version>-jar-with-dependencies.jar cannot launch JavaFX on Apple Silicon Macs because the maven-shade-plugin flattens the OpenJFX mac (x86_64) and mac-aarch64 classifier jars together — they share internal paths (e.g. libprism_es2.dylib), so one overwrites the other and only x86_64 dylibs survive in the fat jar. At runtime dlopen() rejects the wrong-arch dylib and JavaFX dies with No toolkit found. Full reproduction and root cause are documented in #391.

This PR doesn't try to fix the cross-platform fat-jar problem itself (that's a separate decision involving distribution strategy). Instead it sidesteps it by never building a fat jar for macOSjpackage consumes the thin app jar plus individual dependency jars, so each org.openjfx classifier dep stays in its own jar and JavaFX's NativeLibLoader resolves the correct architecture at runtime.

What changed

One new file: distribution/macos/build-macos-installers.sh (~220 lines, executable).

The script:

  1. Stages from the thin jar + jsignpdf/target/dependency/. The maven-dependency-plugin:copy-dependencies execution already in jsignpdf/pom.xml produces this directory at the package phase. No build-graph changes were needed.

  2. Filters wrong-platform classifier jars. Excludes *-win.jar, *-linux.jar, *-mac.jar from the staged set; keeps platform-neutral jars and *-mac-aarch64.jar. Without this, JavaFX could resolve the wrong-arch dylib at startup even outside a fat jar.

  3. Generates a .icns at build time from distribution/linux/flatpak/jsignpdf.png (512×512) using sips + iconutil. No icon resource was added to the repo.

  4. Generates fresh --add-launcher properties files for the three secondary launchers (JSignPdf-swing, JSignPdfC, InstallCert) using only platform-neutral keys, so it doesn't rely on distribution/jpackage/JSignPdfC.properties (which contains Windows-specific win-console/win-shortcut).

  5. Explicitly enumerates the runtime modules. jpackage --add-modules replaces (not extends) the auto-detected set. PKCS#11 (jdk.crypto.cryptoki) is reached only via the existing --add-exports JVM options, so jdeps cannot see the dependency. The script passes --add-modules java.se,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.security.auth,jdk.unsupported,jdk.localedata to guarantee hardware-token support and a complete Swing/AWT runtime.

  6. Reuses distribution/jpackage/common-jvm-options.txt for the same --add-exports/--add-opens set the Windows installer uses, keeping JVM options consistent across platforms.

What was deliberately not changed

  • pom.xml (root) — untouched.
  • jsignpdf/pom.xml — untouched. The cross-platform classifier-collision problem from jar-with-dependencies is unrunnable on Apple Silicon: contains x86_64 macOS JavaFX natives only #391 remains; that's a project-level distribution decision (see "Follow-up work" below) and is out of scope for this PR.
  • distribution/windows/build-windows-installers.ps1 — untouched.
  • distribution/jpackage/common-jvm-options.txt — untouched (kept as the shared single source of truth).
  • The Linux Flatpak build — untouched.

How to build and test locally

Prerequisites: macOS on Apple Silicon, JDK 17+ on PATH (provides jpackage).

mvn -B -DskipTests -pl jsignpdf,installcert -am package
distribution/macos/build-macos-installers.sh --version 3.0.1

Output: distribution/target/upload/JSignPdf-3.0.1-mac-aarch64.dmg (~68 MB).

Verified locally:

  • DMG mounts (license dialog accepts MPL-2.0).
  • JSignPdf.app/Contents/app/ contains only mac-aarch64 and platform-neutral JavaFX classifier jars; no -win.jar/-linux.jar/-mac.jar.
  • All four launcher binaries are present in Contents/MacOS/: JSignPdf, JSignPdf-swing, JSignPdfC, InstallCert.
  • GUI launches and stays alive — JavaFX loads javafx-graphics-21.0.7-mac-aarch64.jar cleanly. The original "no suitable pipeline / no toolkit found" failure from jar-with-dependencies is unrunnable on Apple Silicon: contains x86_64 macOS JavaFX natives only #391 is gone.
  • CLI: JSignPdfC --help works; the Unknown module: jdk.crypto.cryptoki warning that's visible without explicit module enumeration is resolved.

Known caveats / follow-up work

These are intentionally out of scope for this PR but worth tracking:

1. Code signing and notarization

The DMG is currently produced unsigned and unnotarized. End-users will see Gatekeeper warnings on first open ("JSignPdf cannot be opened because the developer cannot be verified" or similar) and have to right-click → Open, or run xattr -dr com.apple.quarantine /Applications/JSignPdf.app.

Adding signing requires:

  • An Apple Developer ID Application certificate (for app signing) installed in the build machine's keychain.
  • An Apple Developer ID Installer certificate (for --type pkg if added later).
  • An app-specific password or App Store Connect API key for the notarization service.

Once those are in place, jpackage flags to add:

--mac-sign
--mac-signing-key-user-name "Developer ID Application: <Name> (<TeamID>)"
--mac-signing-keychain "<keychain-path>"   # optional
--mac-package-identifier  com.intoolswetrust.jsignpdf
--mac-package-name        JSignPdf

Notarization is a separate step run after jpackage finishes:

xcrun notarytool submit <dmg> --apple-id <id> --team-id <team> --password <app-pw> --wait
xcrun stapler staple <dmg>

2. Intel (x86_64) build

This PR ships arm64 only. jpackage does not cross-compile across Mac architectures — each arch must be built on its native host. An Intel DMG would require either an x86_64 macOS GitHub runner (macos-13 and earlier are Intel; macos-14+ are arm64) or a separate dedicated builder. The script as-is can be reused on x86_64 by changing the architecture check at the top and the output filename suffix; no other changes needed.

A "universal" DMG (containing both architectures via a fat app bundle) is technically possible with lipo-merged JDK runtimes but is significantly more work and not standard jpackage output.

3. CI integration

This PR adds the script but does not wire it into a GitHub Actions workflow. Mirroring build-windows-installers.ps1's integration would mean adding a job that:

  • Runs on macos-14 (or newer arm64 image).
  • Sets up JDK 21 (matching the project's release enforcer profile).
  • Runs mvn -B -DskipTests -pl jsignpdf,installcert -am package.
  • Runs distribution/macos/build-macos-installers.sh --version ${{ inputs.version }}.
  • Uploads distribution/target/upload/JSignPdf-*-mac-aarch64.dmg as a release artifact.

Happy to follow up with a separate PR for this once this script lands.

4. Underlying fat-jar problem (#391)

This PR works around the classifier-collision issue for macOS distribution but doesn't fix it for users who download the shaded jar directly. The four candidate fixes are listed in #391; whichever direction the project chooses, the script in this PR would still be the right way to build the macOS-native installer.

Mirrors distribution/windows/build-windows-installers.ps1 to produce
JSignPdf-<version>-mac-aarch64.dmg via jpackage.

Avoids the cross-platform fat-jar JavaFX classifier collision (intoolswetrust#391) by
staging the thin app jar plus jsignpdf/target/dependency/ and filtering
out wrong-platform classifier jars (-win.jar, -linux.jar, -mac.jar) at
build time, keeping only -mac-aarch64.jar. Reuses the shared
distribution/jpackage/common-jvm-options.txt for PKCS#11 access flags
and explicitly enumerates the runtime modules so jdk.crypto.cryptoki
and the standard java.se aggregator are included.

Refs intoolswetrust#391

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 9, 2026 11:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an initial macOS Apple Silicon (arm64) distribution path by introducing a jpackage-based DMG build script that packages JSignPdf from the thin jar plus dependency jars (avoiding the OpenJFX classifier collision that breaks the shaded fat jar on Apple Silicon).

Changes:

  • Add distribution/macos/build-macos-installers.sh to build an arm64 .app and .dmg via jpackage.
  • Stage app payload from the thin jar + jsignpdf/target/dependency/, filtering out non-macOS classifier jars.
  • Generate a macOS .icns icon at build time and reuse shared JVM options from distribution/jpackage/common-jvm-options.txt.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

VERSION=""
while [[ $# -gt 0 ]]; do
case "$1" in
--version) VERSION="${2:-}"; shift 2 ;;
Comment on lines +8 to +12
# Prerequisites on the build machine:
# * macOS on Apple Silicon (arm64)
# * JDK 17+ on PATH (provides jpackage)
# * jsignpdf and installcert modules already built:
# mvn -B -DskipTests -pl jsignpdf,installcert -am package
Comment on lines +56 to +63
# non-numeric suffix (e.g. "-RC1", "-SNAPSHOT") and keep up to three numeric
# components. $VERSION itself is preserved for release-tag-aligned filenames.
APP_VERSION=$(echo "$VERSION" \
| sed -E 's/[^0-9.].*$//' \
| awk -F. '{
n = (NF > 3 ? 3 : NF);
for (i = 1; i <= n; i++) printf("%s%s", (i>1?".":""), $i);
printf("\n");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

jar-with-dependencies is unrunnable on Apple Silicon: contains x86_64 macOS JavaFX natives only

2 participants