← Library

Copy · intermediate

Audit a Mac app for Intel-only binaries before Rosetta goes away

A small Bash check that finds Intel-only code hidden inside a macOS app bundle before the general-purpose Rosetta deadline.

A Mac app can open normally on Apple silicon and still contain one Intel-only helper, plug-in or updater. Rosetta hides that gap today. It will not hide it forever.

On September 9, Apple opened App Store submissions for the latest OS releases and repeated the first deadline: macOS 26 is the final release for Intel Macs, while macOS 27 runs only on Apple silicon. There is a second deadline for software. Apple says general-purpose Rosetta remains available through macOS 27, then macOS 28 limits Rosetta to certain older games that depend on Intel frameworks.

Those are different transitions. A universal app can still support people on macOS 26 while running natively on Apple silicon. An Apple-silicon-only app can drop the Intel slice. Both choices work after Rosetta; an x86_64-only binary does not.

Run the audit

Save this as audit-arm64.sh, then point it at the release .app bundle:

#!/usr/bin/env bash
set -euo pipefail

app=${1:?Usage: audit-arm64.sh MyApp.app}
status=0

while IFS= read -r -d '' binary; do
  if ! architectures=$(lipo -archs "$binary" 2>/dev/null); then
    continue
  fi

  case " $architectures " in
    *" arm64 "*|*" arm64e "*) ;;
    *)
      printf 'missing Apple-silicon slice\t%s\t%s\n' "$architectures" "$binary"
      status=1
      ;;
  esac
done < <(find "$app" -type f -print0)

exit "$status"
chmod +x audit-arm64.sh
./audit-arm64.sh "build/Release/MyApp.app"

The script asks lipo about every regular file, so it sees Mach-O executables inside nested frameworks, plug-ins and helper bundles rather than checking only the app’s main executable. Assets and scripts are ignored because lipo cannot read them.

No output and exit code 0 means every Mach-O file that the script found has an Apple-silicon slice. A failure names the architecture and path:

missing Apple-silicon slice  x86_64  MyApp.app/Contents/Frameworks/Legacy.framework/Legacy

Run it on the artifact you distribute, not a local debug build. Xcode normally builds release targets with standard architectures, but a prebuilt dependency can carry an Intel-only binary into the finished bundle. Apple’s universal binary guide explicitly includes frameworks, plug-ins, libraries, command-line tools and daemons in the migration inventory.

Decide what each result means

  • If your app still supports Intel Macs on macOS 26, rebuild the failing component as a universal binary containing x86_64 and arm64.
  • If your next release targets only Apple silicon, an arm64 build is enough. Remove Intel-only components instead of preserving an unused slice.
  • If the component comes from a vendor, update or replace it. Rebuilding only your main target cannot add an architecture to a closed binary dependency.
  • If users install plug-ins separately, audit those packages too. They are not present inside the app bundle this script scans.

Apple’s porting guide notes that all code loaded into one process must support the same architecture. That is why one forgotten plug-in matters even when the application executable already says arm64.

Where this stops

This is an inventory check, not a compatibility test. It will not catch architecture assumptions in source code, a helper downloaded after install, or a feature that fails only at runtime. After the script passes, run the signed release on an Apple silicon Mac and exercise updates, plug-ins and background helpers. Keep that smoke test in the release checklist.

The takeaway

Do not treat “the app launches on my Mac” as evidence that the whole product is ready for the end of Rosetta. Inspect the shipped bundle now. One short check turns a vague migration deadline into a named list of binaries you can rebuild, replace or remove.

Sources

Knowledge retrieval

What are you working through?

Start typing to search every guide, video, tool and snippet.