How can I distinguish ARM binaries from x86 binaries on macOS?
Is there something I can type on the command-line to determine if an executable is an M1 binary or an x86 binary?
You can use the file
command to see which architectures a binary (or library) includes native code for. The M1 processor uses the 64-bit ARM architecture, so it'll be listed as "arm64". I don't have an M1 Mac or any ARM-only binaries handy, but compare the Chrome (Intel-only) and Firefox ("universal"/"fat" binary supporting both Intel and ARM) on my Mac:
$ file /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome
/Applications/Google Chrome.app/Contents/MacOS/Google Chrome: Mach-O 64-bit executable x86_64
$ file /Applications/Firefox.app/Contents/MacOS/firefox
/Applications/Firefox.app/Contents/MacOS/firefox: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
/Applications/Firefox.app/Contents/MacOS/firefox (for architecture x86_64): Mach-O 64-bit executable x86_64
/Applications/Firefox.app/Contents/MacOS/firefox (for architecture arm64): Mach-O 64-bit executable arm64
And here's a library:
$ file /Applications/Firefox.app/Contents/MacOS/libmozglue.dylib
/Applications/Firefox.app/Contents/MacOS/libmozglue.dylib: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit dynamically linked shared library x86_64] [arm64:Mach-O 64-bit dynamically linked shared library arm64]
/Applications/Firefox.app/Contents/MacOS/libmozglue.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
/Applications/Firefox.app/Contents/MacOS/libmozglue.dylib (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
Update: I checked an M1 Mac, and it looks like it has Intel+ARM fat binaries (which is the same as Big Sur installed on an Intel Mac):
$ file /System/Applications/Chess.app/Contents/MacOS/Chess
/System/Applications/Chess.app/Contents/MacOS/Chess: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
/System/Applications/Chess.app/Contents/MacOS/Chess (for architecture x86_64): Mach-O 64-bit executable x86_64
/System/Applications/Chess.app/Contents/MacOS/Chess (for architecture arm64e): Mach-O 64-bit executable arm64e
Note that the architecture is listed as "arm64e". The "e" is a subarchitecture indicator; see this question for more info. Looking at /usr/share/file/magic/mach (which holds the magic codes file
uses to recognize these file types), there's also an "arm64_v8" subarchitecture (which I think this question addresses).
And just for fun, here's the Chess app from way back in OS X v10.5, which included native code for both PowerPC and Intel, each in both 32- and 64-bit:
$ file /Applications/Chess.app/Contents/MacOS/Chess
/Applications/Chess.app/Contents/MacOS/Chess: Mach-O universal binary with 4 architectures
/Applications/Chess.app/Contents/MacOS/Chess (for architecture ppc): Mach-O executable ppc
/Applications/Chess.app/Contents/MacOS/Chess (for architecture ppc64): Mach-O 64-bit executable ppc64
/Applications/Chess.app/Contents/MacOS/Chess (for architecture i386): Mach-O executable i386
/Applications/Chess.app/Contents/MacOS/Chess (for architecture x86_64): Mach-O 64-bit executable x86_64
On macOS you can have three flavors of app currently being built, A, B and AB. lipo
reveals the build steps the developer chose.
% lipo -archs /System/Applications/Mail.app/Contents/MacOS/Mail
x86_64 arm64
Apple documents this in a long article — jump to the part where it describes the command line build steps for the two “flavors” of current binary and the lipo
command that mixes a universal binary from the two. The -target is what results in a binary being a specific format (not just x86_64 but Apple and tied to a specific version of macOS SDK)
x86_app: main.c
$(CC) main.c -o x86_app -target x86_64-apple-macos10.12
arm_app: main.c
$(CC) main.c -o arm_app -target arm64-apple-macos11
universal_app: x86_app arm_app
lipo -create -output universal_app x86_app arm_app
To see the architectures present in a built executable file, run the
lipo
orfile
command-line tools.
- https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary/
Note, the tools work on binaries embedded in the app framework as opposed to the app folder/package that most people call "the app".
The file
command is more verbose so I prefer lipo
for scripting checks or getting details of a binary.