Tuesday, January 19, 2021


Tags

macOS CPU Architecture

With the upcoming transition, it's a good idea to know the architecture of your app and the system it's running on.

Tuesday, January 19, 2021 - Sam Rowlands

Update: Jan 19th 2021

To make it easier to understand how this code works, I've created a sample project, which can be downloaded from blog/202032/ARM_tester.zip. I've also updated some of the samples below.

Original post date: Aug 6th, 2020

Detecting System CPU Architecture

I am certain there are more ways than I am going to list, which can be used to detect what kind of CPU your customers Mac is using, but I'm going to go with the following.

  1. uname -m This simple terminal command (can be called from a Xojo shell) returns one of the following. i386 = Intel 32-Bit x86_64 = Intel 64-Bit arm64 = Apple Silicon 64-Bit*
  2. Declare function Gestalt lib "CoreServices" (inSelector as OSType, byRef response as Int32) as Int32 const gestaltSysArchitecture = "sysa" Dim r as int32 Dim err as integer = gestalt( gestaltSysArchitecture, r ) Use the "Gestalt" system API, which returns one of the following possibilities. 2 = PowerPC 10 = Intel 20 = Apple Silicon

    Gestalt was marked as deprecated in Mac OS X 10.8, yet the Arm value was added for macOS 11.

  3. The final option, comes at the suggestion of Thomas Tempelmann (apps.tempel.org). Which is to use the sysctl API. declare function sysctlbyname lib "/usr/lib/libSystem.dylib" (name as cString, out as ptr, byref size as Uinteger, newP as ptr, newPSize as Uinteger) as integer Dim sizeInfo as Uinteger // --- Request the size of the data so I can allocate a memory block for it. if sysctlbyname( "hw.cputype", nil, sizeInfo, nil, 0 ) <> 0 then break MsgBox "There's a problem collecting the CPUType in " + currentmethodName return 0 end if Dim mb as new memoryBlock( sizeInfo ) // --- Now we have the right sized memory block. call sysctlbyname( "hw.cputype", mb, sizeInfo, nil, 0 ) Dim r as integer = mb.uint32Value( 0 )

    This option is my favorite as it should list the same codes that I already use with NSRunningApplication and when spelunking through Mach-O files.

    Const CPU_TYPE_POWERPC as Integer = 18 Const CPU_TYPE_INTEL as Integer = 7 Const CPU_TYPE_ARM as Integer = 12 Const CPU_ARCH_ABI64 as Integer = 16777216

    The first three values are the CPU Architecture, and the last one is for detecting if it's 64-Bit or not. Thomas supplied me with the result from his ARM DTK* "16777228" which contains CPU_ARCH_ABI64 + CPU_TYPE_ARM. However running it on 2020 16" MacBook Pro (i9), only returns CPU_TYPE_INTEL.

    We can fix the incorrect 64-Bit identifier by checking the value "hw.cpu64bit_capable". sysctlbyname( "hw.cpu64bit_capable", mb, sizeInfo, nil, 0 ) If the value of "hw.cpu64bit_capable" = 1, then we can make sure that our CPU_TYPE has the 64-Bit flag set, with the following code. result = bitwise.bitor( result, CPU_ARCH_ABI64 )

* The values are from macOS Big Sur Beta 3, they may change before final release.

Detecting Application CPU Architecture

Again there are many ways to do this.

  1. NSRunningApplication will return the same codes as sysctl (except it correctly has 64-Bit set on the 2020 16" MacBook Pro).
  2. Reading the Mach-O file will return the same codes as sysctl (except it correctly has 64-Bit set on the 2020 16" MacBook Pro).
  3. lipo -archs <shellpathtomachofile> returns "x86_64 arm64e" for Safari on macOS Big Sur. This must be called on the Mach-O executable in "/Contents/MacOS/".

All of these mechanisms will be present in version 1.0.5 of the Ohanaware App Kit. Along with architectureDisplayName(inArchitecture as integer) as string which provides a unified mechanism for converting the CPU_TYPE codes into something human readable.