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 or file 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.