Add a macOS Universal Binary (universal-apple-darwin) build target combining x86_64 (Intel) and arm64 (Apple Silicon) architectures into a single fat Mach-O executable and .dmg package, while retaining dedicated single-architecture builds (x86_64 and arm64).
Upstream Dependency
Important
Blocked by Upstream: Depends on gronod/argyllcms#27 (macOS Universal Binary release archive).
ICCery's Universal build will directly vendor and bundle the universal build of ArgyllCMS (Argyll_V<version>_macOS_universal_bin.tgz), ensuring all bundled sidecar utilities (instlist, targen, printtarg, chartread, average, colprof, profcheck, iccgamut) are themselves universal fat Mach-O binaries.
Current Architecture & Limitations
CI Build Matrix: Workflows currently build two separate packages:
Intel: target: x86_64-apple-darwin on macos-15-intel runner
Apple Silicon: target: aarch64-apple-darwin on macos-15 runner
ArgyllCMS Sidecar Bundling:
scripts/fetch-argyll.mjs downloads and stages single-architecture binaries into src-tauri/argyll/<platform> (macos-x86_64 or macos-aarch64).
resolve_binary in src-tauri/src/commands.rs resolves binaries using the platform directory.
For the universal build, vendoring the universal ArgyllCMS release archive into src-tauri/argyll/macos-universal/ ensures native execution across all Macs with identical paths.
When --platform=macos-universal is supplied, download and extract Argyll_V<version>_macOS_universal_bin.tgz from gronod/argyllcms releases into src-tauri/argyll/macos-universal/.
Ensure executable permissions (chmod 0755) are verified for all staged binaries.
2. Tauri Configuration & Binary Resolution
Update resolve_binary() in src-tauri/src/commands.rs:
letplatform=match(std::env::consts::OS,std::env::consts::ARCH){("linux","x86_64")=>"linux-x86_64",("windows","x86_64")=>"windows-x86_64",("macos","aarch64")=>{// Check for universal binary resource first, then fallback to arch-specific
ifapp.path().resolve("argyll/macos-universal/instlist",tauri::path::BaseDirectory::Resource).map(|p|p.exists()).unwrap_or(false){"macos-universal"}else{"macos-aarch64"}},("macos","x86_64")=>{ifapp.path().resolve("argyll/macos-universal/instlist",tauri::path::BaseDirectory::Resource).map(|p|p.exists()).unwrap_or(false){"macos-universal"}else{"macos-x86_64"}},_=>"linux-x86_64",};
Tauri v2 natively merges x86_64 and aarch64 into a single universal bundle when invoking:
npm run tauri build -- --target universal-apple-darwin
Stage ICCery_${TAG}-${SHORT_SHA}-macos-universal.dmg and ICCery_${TAG}-${SHORT_SHA}-macos-universal.zip.
Upload to release assets.
Verification & Acceptance Criteria
Binary Architecture Confirmation:
Running file on both the main application executable and all bundled ArgyllCMS sidecar binaries confirms fat universal binaries: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
Native Execution:
App and subprocesses execute natively without Rosetta 2 on Apple Silicon (M1/M2/M3/M4) and on Intel x86_64 Macs.
Release Assets:
Release assets contain ICCery_<ver>-macos-universal.dmg and .zip alongside x86_64 and arm64 assets.
### Overview & Objective
Add a macOS **Universal Binary** (`universal-apple-darwin`) build target combining `x86_64` (Intel) and `arm64` (Apple Silicon) architectures into a single fat Mach-O executable and `.dmg` package, while retaining dedicated single-architecture builds (`x86_64` and `arm64`).
---
### Upstream Dependency
> [!IMPORTANT]
> **Blocked by Upstream**: Depends on **[gronod/argyllcms#27](https://git.i3omb.com/gronod/argyllcms/issues/27)** (macOS Universal Binary release archive).
>
> ICCery's Universal build will directly vendor and bundle the **universal build of ArgyllCMS** (`Argyll_V<version>_macOS_universal_bin.tgz`), ensuring all bundled sidecar utilities (`instlist`, `targen`, `printtarg`, `chartread`, `average`, `colprof`, `profcheck`, `iccgamut`) are themselves universal fat Mach-O binaries.
---
### Current Architecture & Limitations
1. **CI Build Matrix**: Workflows currently build two separate packages:
- Intel: `target: x86_64-apple-darwin` on `macos-15-intel` runner
- Apple Silicon: `target: aarch64-apple-darwin` on `macos-15` runner
2. **ArgyllCMS Sidecar Bundling**:
- `scripts/fetch-argyll.mjs` downloads and stages single-architecture binaries into `src-tauri/argyll/<platform>` (`macos-x86_64` or `macos-aarch64`).
- `resolve_binary` in `src-tauri/src/commands.rs` resolves binaries using the platform directory.
- For the universal build, vendoring the universal ArgyllCMS release archive into `src-tauri/argyll/macos-universal/` ensures native execution across all Macs with identical paths.
---
### Required Changes
#### 1. Build Script & Sidecar Preparation (`scripts/fetch-argyll.mjs`)
- Add support for `macos-universal` platform in `PLATFORMS`:
```javascript
'macos-universal': {
assetSuffix: '_macOS_universal_bin.tgz',
markerBinary: 'instlist',
destDir: path.join(TAURI_ARGYLL_DIR, 'macos-universal'),
isWindows: false,
},
```
- When `--platform=macos-universal` is supplied, download and extract `Argyll_V<version>_macOS_universal_bin.tgz` from `gronod/argyllcms` releases into `src-tauri/argyll/macos-universal/`.
- Ensure executable permissions (`chmod 0755`) are verified for all staged binaries.
#### 2. Tauri Configuration & Binary Resolution
- Update `resolve_binary()` in `src-tauri/src/commands.rs`:
```rust
let platform = match (std::env::consts::OS, std::env::consts::ARCH) {
("linux", "x86_64") => "linux-x86_64",
("windows", "x86_64") => "windows-x86_64",
("macos", "aarch64") => {
// Check for universal binary resource first, then fallback to arch-specific
if app.path().resolve("argyll/macos-universal/instlist", tauri::path::BaseDirectory::Resource).map(|p| p.exists()).unwrap_or(false) {
"macos-universal"
} else {
"macos-aarch64"
}
},
("macos", "x86_64") => {
if app.path().resolve("argyll/macos-universal/instlist", tauri::path::BaseDirectory::Resource).map(|p| p.exists()).unwrap_or(false) {
"macos-universal"
} else {
"macos-x86_64"
}
},
_ => "linux-x86_64",
};
```
- Tauri v2 natively merges `x86_64` and `aarch64` into a single universal bundle when invoking:
```bash
npm run tauri build -- --target universal-apple-darwin
```
- Ensure `tauri.conf.json` resource globs (`"argyll/**/*"`) bundle `argyll/macos-universal/`.
#### 3. CI Workflow Updates (`build-macos.yml`)
- Update the build matrix to include the universal target on `macos-15` runner:
```yaml
matrix:
platform:
- name: Intel
os: macos-15-intel
target: x86_64-apple-darwin
binary_dir: macos-x86_64
arch: x86_64
- name: Apple Silicon
os: macos-15
target: aarch64-apple-darwin
binary_dir: macos-aarch64
arch: arm64
- name: Universal (Intel + Apple Silicon)
os: macos-15
target: universal-apple-darwin
binary_dir: macos-universal
arch: universal
```
- **Rust Toolchain Setup**: When building `universal-apple-darwin`, install both target architectures on the runner:
```bash
rustup target add x86_64-apple-darwin aarch64-apple-darwin
```
- **Argyll Fetch Step**: For `universal-apple-darwin`, invoke `npm run fetch-argyll -- --platform macos-universal`.
- **Tauri Build Step**: Execute `npm run tauri build -- --target ${{ matrix.platform.target }}`.
- **Packaging & Artifact Staging**:
- Stage `ICCery_${TAG}-${SHORT_SHA}-macos-universal.dmg` and `ICCery_${TAG}-${SHORT_SHA}-macos-universal.zip`.
- Upload to release assets.
---
### Verification & Acceptance Criteria
1. **Binary Architecture Confirmation**:
- Running `file` on both the main application executable and all bundled ArgyllCMS sidecar binaries confirms fat universal binaries:
`Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]`
2. **Native Execution**:
- App and subprocesses execute natively without Rosetta 2 on Apple Silicon (M1/M2/M3/M4) and on Intel x86_64 Macs.
3. **Release Assets**:
- Release assets contain `ICCery_<ver>-macos-universal.dmg` and `.zip` alongside `x86_64` and `arm64` assets.
gronod
added this to the Milestone 9: macOS Native Support & Enhanced Print Spooling (v0.4.0) milestone 2026-08-31 23:52:13 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Overview & Objective
Add a macOS Universal Binary (
universal-apple-darwin) build target combiningx86_64(Intel) andarm64(Apple Silicon) architectures into a single fat Mach-O executable and.dmgpackage, while retaining dedicated single-architecture builds (x86_64andarm64).Upstream Dependency
Current Architecture & Limitations
target: x86_64-apple-darwinonmacos-15-intelrunnertarget: aarch64-apple-darwinonmacos-15runnerscripts/fetch-argyll.mjsdownloads and stages single-architecture binaries intosrc-tauri/argyll/<platform>(macos-x86_64ormacos-aarch64).resolve_binaryinsrc-tauri/src/commands.rsresolves binaries using the platform directory.src-tauri/argyll/macos-universal/ensures native execution across all Macs with identical paths.Required Changes
1. Build Script & Sidecar Preparation (
scripts/fetch-argyll.mjs)macos-universalplatform inPLATFORMS:--platform=macos-universalis supplied, download and extractArgyll_V<version>_macOS_universal_bin.tgzfromgronod/argyllcmsreleases intosrc-tauri/argyll/macos-universal/.chmod 0755) are verified for all staged binaries.2. Tauri Configuration & Binary Resolution
resolve_binary()insrc-tauri/src/commands.rs:x86_64andaarch64into a single universal bundle when invoking:tauri.conf.jsonresource globs ("argyll/**/*") bundleargyll/macos-universal/.3. CI Workflow Updates (
build-macos.yml)macos-15runner:universal-apple-darwin, install both target architectures on the runner:universal-apple-darwin, invokenpm run fetch-argyll -- --platform macos-universal.npm run tauri build -- --target ${{ matrix.platform.target }}.ICCery_${TAG}-${SHORT_SHA}-macos-universal.dmgandICCery_${TAG}-${SHORT_SHA}-macos-universal.zip.Verification & Acceptance Criteria
fileon both the main application executable and all bundled ArgyllCMS sidecar binaries confirms fat universal binaries:Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]ICCery_<ver>-macos-universal.dmgand.zipalongsidex86_64andarm64assets.