Apple Silicon Macs (M1, M2, M3, and M4 series) utilize the 64-bit ARM architecture (arm64). While modern macOS software is compiled natively for Apple Silicon, developers frequently encounter legacy CLI tools, Python C-extensions, or containerized binaries compiled exclusively for Intel x86_64 processors. Through Apple’s Rosetta 2 translation layer and the built-in arch command-line utility, you can selectively invoke binaries or spawn entire shell environments under x86_64 emulation or native arm64 execution on demand.
Understanding Universal Binaries and Architecture Translation
Universal 2 binaries contain distinct compiled slices for both arm64 and x86_64 within a single Mach-O file. By default, macOS automatically selects the native arm64 slice on Apple Silicon hardware. However, when compiling software against legacy dependencies that lack ARM support, you must force the system to invoke the x86_64 slice through Rosetta 2. The arch utility changes the target architecture before passing execution to the target binary.
Syntax and Key Options
arch -arch_name command [arguments]
-arm64: Forces execution using the native 64-bit ARM slice.-arm64e: Runs with pointer authentication code (PAC) support enabled.-x86_64: Forces execution through Rosetta 2 Intel emulation.-x86_64h: Runs the Haswell-optimised 64-bit Intel architecture slice.
Step-by-Step Practical Implementation
Step 1: Check Your Current Shell Architecture
- Open Terminal from
/Applications/Utilities/. - Run the
uname -mcommand:uname -m - On Apple Silicon, this returns
arm64. If running under Rosetta emulation, it returnsx86_64.
Step 2: Inspect Binary Architecture Slices
Before forcing an architecture, verify which slices exist inside a Mach-O executable using file or lipo:
file /usr/bin/uname
Output demonstrates a universal executable:
/usr/bin/uname: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
Step 3: Run an Individual Command Under Rosetta 2
To run a command under x86_64 emulation without altering your global shell configuration, prefix it with arch -x86_64:
arch -x86_64 uname -m
Terminal executes through Rosetta 2 and outputs: x86_64.
Step 4: Launch an Emulated x86_64 Subshell
If you are building an extensive project with multiple legacy npm or Python dependencies, running every command with a prefix is tedious. Launch an interactive Zsh subshell entirely under Rosetta:
arch -x86_64 zsh
Any subcommands, compilers, or build scripts run inside this session will execute within the x86_64 runtime environment automatically.
To return to your native Apple Silicon shell, simply enter:
exit
Step 5: Managing Dual Homebrew Environments
Apple Silicon systems typically maintain two separate Homebrew installations: native ARM at /opt/homebrew and Rosetta Intel at /usr/local. To install Intel-only packages, invoke the x86_64 Homebrew binary:
arch -x86_64 /usr/local/bin/brew install legacy-package
Architecture Comparison on Apple Silicon
| Execution Mode | Architecture Flag | Translation Engine | Performance Profile | Primary Use Case |
|---|---|---|---|---|
| Native Apple Silicon | -arm64 |
Direct Silicon Execution | Maximum throughput and efficiency | Everyday development, production builds, and native CLI tools |
| Rosetta 2 Emulation | -x86_64 |
Apple Rosetta 2 JIT / AOT | ~70-85% native performance | Compiling unported C-extensions and running legacy x86 CLIs |
| Pointer Authentication | -arm64e |
Hardware PAC on Apple Silicon | Native with enhanced kernel security | Security research and system daemon debugging |
Troubleshooting Common Errors
- “Bad CPU type in executable”: Rosetta 2 is not installed on your Mac. Install it via Terminal with
softwareupdate --install-rosetta --agree-to-license. - Architecture Mismatch in Compilers: Attempting to link an x86_64 static library against an arm64 binary generates an
ld: symbol(s) not found for architecture arm64error. Ensure all dependencies are built using the matchingarch -x86_64environment.