How to Detect Apple Silicon and Rosetta from within a Shell Script

Apple Silicon laptops debuted with outstanding performance numbers – being among the highest-performing laptop microprocessors as measured by GeekBench and many others. The M1 processors‘ power efficiencies are very much commendable – potentially providing 10 hours of continuous video-conferencing time on a single charge. Although the user’s psychological power would probably peter out prior to the portable 😅.

But with great power comes… great lack of support? 

“ … my development environment requires a few of the GNU developer tools … these tools crash with an Abort Trap: 6 error …”
“ … Every CMake project needs significant hacks. “
“ … Is there a Fortran compiler available? I tried building gfortran, but ran into some difficulty … What’s the current recommendation for building Fortran dependencies for Apple Silicon?“
“ … The GCC project is coded in custom assembly for each chip … the parts that emit assembly … ”

Sadly open source support for the speedy silicon is still stuttering. Large portions of these software are dependent on compilers that have yet to fully support the architecture. Examples include the GNU Compiler Collection (gcc) and Fortran — that latter one being an established yet hidden worker bee behind many numerical computing collections.

GCC arm64-darwin support is suspended

It looks like large portions of open source software would still need to run under Rosetta 2, the Mac’s emulation (and translation) system to run Intel-based applications, in the foreseeable future. At least until the open source communities at large internalizes importance to support the architecture.

A compiled native application would always know what the CPU architecture it is running on. It was built for the architecture in the first place. Its source code uses conditional compilation to detect its target architecture and thus branches accordingly at build time.

However a script doesn’t have the same benefit. Being interpreted and cross-architecture, the program would need to determine what is the underlying architecture as at run-time.

Why is this important? Script interpreters built-in to macOS (such as shell scripts and OSA interpreters) are Universal Binaries. In an Apple Silicon mac, they can run in both Arm and Intel modes. By default macOS preserves the architecture of process subtrees. An Intel process (under Rosetta 2) would launch sub-processes in Intel mode when possible. Likewise an Arm process would prefer the arm64 slice of universal binaries that it launches.

This process architecture preservation is useful most of the time. But it could present a problem when running a complex build system having portions need to run in Intel mode yet some other portions would run in Arm mode. There would be times when a build script would need to find out what is the current mode and act accordingly, such as setting a different folder path appropriate for the respective architecture target.

Wouldn’t it be great if a script could detect whether it is running under native Intel, Rosetta 2, or native Arm?

What about forcing Rosetta mode for a few lagging sub-projects that have not support the new architecture?

Read on to find out how.

Detecting the Processor Architecture and Emulation Status

The trusty uname POSIX utility would show the CPU architecture. When running on an Apple Silicon mac, the command uname -m would print arm64 whereas on Intel it would say x86_64. Although it does not differentiate between Genuine Intel and Rosetta 2.

Fortunately Rosetta 2 provides a peephole that identifies itself from processes running under it. This is the sysctl.proc_translated flag that can be accessed through the sysctl -n command.

Using these these two commands, I’ve put together a Z Shell script that shows which processor (real or emulated) that the script is running on.

#!/bin/zsh

arch_name="$(uname -m)"

if [ "${arch_name}" = "x86_64" ]; then
    if [ "$(sysctl -in sysctl.proc_translated)" = "1" ]; then
        echo "Running on Rosetta 2"
    else
        echo "Running on native Intel"
    fi  
elif [ "${arch_name}" = "arm64" ]; then
    echo "Running on ARM"
else
    echo "Unknown architecture: ${arch_name}"
fi

Enforcing Intel Emulation

Arm-based Macs can run both Apple Silicon and Intel binaries. In a Universal 2 binary containing both Arm and Intel slices, the computer can run it both natively and under Rosetta 2.

Forcing command-line apps to run to under Intel mode could be useful to build projects that are not compatible to cross-compilation and hasn’t supported Apple Silicon natively. It’ll let cross-platform build scripts to see that it is running on an Intel Mac and let it run as it has always been since 2007.

You can use the arch command to start processes to run in another instruction set different from its parent process, when support is present (that is, the universal binary has the appropriate architecture slice and the system can execute that alternative slice).

For example, the following command would run the shell under Rosetta 2 in an Apple Silicon mac. Therefore all other applications started by this shell session would run as an Intel application and system calls such as uname would report an Intel processor.

arch -x86_64 zsh

In contrast the following would force run the shell in Arm native mode. This could be useful when a script running in Intel mode would need to switch back to running natively.

arch -arm64 zsh

Of course in an Intel-based mac, the second command would fail with an arch: Unknown architecture: arm64 error. Apple do not provide arm64 emulation for Intel processors as of this writing.

macOS Version Change

Another big change with macOS “Big Sur” is the version number. It has gone up to 11 as well as a new product name, “macOS”. This could break some scripts that expects the operating system name to be “Mac OS X” and version number start with 10, as it has been since 2001.

To alleviate this, Apple provides a special environment variable SYSTEM_VERSION_COMPAT. When it has the value 1, the operating system would report a name of “Mac OS X and 10.16 as its version.

export SYSTEM_VERSION_COMPAT=1

Example below:

Big Sur version number compatibility environment variable

Next Steps

If you’re trying to build an open source application under Big Sur using an Apple Silicon processor, try forcing it to run under Rosetta 2. That should isolate whether the problem comes from the operating system or the processor architecture.

If you’re working on open source projects, maybe it’s a good time to update it to support Apple Silicon. These shell script commands could help you in adopting your build system in detecting the true processor architecture that it runs on and make the appropriate decision.



Avoid App Review rules by distributing outside the Mac App Store!


Get my FREE cheat sheets to help you distribute real macOS applications directly to power users.

* indicates required

When you subscribe you’ll also get programming tips, business advices, and career rants from the trenches about twice a month. I respect your e-mail privacy.

0 thoughts on “How to Detect Apple Silicon and Rosetta from within a Shell Script

Leave a Reply