C++/C Code to have different execution block on M1 and Intel
Asked Answered
H

4

5

I am writing a code for macOS application. The application would be running on M1 based Macs as well as Intel based Macs also. What would be the switch to differentiate M1 and Intel?

if (M1)
{
   do something for M1
}
else if (Intel)
{
   do something for Intel
}
Hawken answered 18/2, 2021 at 8:34 Comment(0)
C
4

I think, you can use __arm__ to detect arm architecture:

#ifdef __arm__
//do smth on arm (M1)
#else
//do smth on x86 (Intel)
#endif
Cushman answered 18/2, 2021 at 8:40 Comment(4)
Note to the OP, who I suspect is under the false impression they're going to be able to do this in-code with a single build: you can't. The above solution will build two different versions, dependent and based on the toolchain used, the chosen target platform at build-time, and the predefined macros provided therein. The result is two different builds; one for M1 and one for anything-not-arm, and distribution of said-same to the appropriate target is on the onus of the OP.Diffluent
When you archive an application, the Xcode creates a fat application or library (one executor has code for both platform). If you just build (with a run button), you will get application only for one platform (not for all).Cushman
To detect a processor name, you can use "hw.cputype", #19859888 . But, I think, also you will want to detect emulation mode for your application: developer.apple.com/forums/thread/652667Cushman
For me, __arm__ was not defined on my M1 MacBook Pro. I had to use __arm64__.Endor
A
4

I was just fooling around with this and found this reference for Objective-C from apple that seemed to work with clang for C++.

// Objective-C example
#include "TargetConditionals.h"
#if TARGET_OS_OSX
  // Put CPU-independent macOS code here.
  #if TARGET_CPU_ARM64
    // Put 64-bit Apple silicon macOS code here.
  #elif TARGET_CPU_X86_64
    // Put 64-bit Intel macOS code here.
  #endif
#elif TARGET_OS_MACCATALYST
   // Put Mac Catalyst-specific code here.
#elif TARGET_OS_IOS
  // Put iOS-specific code here.
#endif

https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary

I specifically checked to see if TARGET_CPU_ARM64 was defined in my header.

Hopefully this helps someone.

Abnegate answered 28/3, 2022 at 18:7 Comment(0)
R
3

you can use #ifdef __arm64__ or __arm64. Found out with the useful command

echo | gcc -dM -E - 

echo | gcc -dM -E - | grep -i arm
Ragan answered 27/9, 2023 at 12:8 Comment(1)
echo | gcc -dM -E - | grep -i arm. This is a quite helpful command! Thanks! Using it I was able to find that only __arm64 and __arm64__ are defined, not __arm__Ussery
W
1

If you need a runtime check instead of compile time check, you can think of using something like below

#include <sys/sysctl.h>
#include <mach/machine.h>

int main(int argc, const char * argv[]) 
{
    cpu_type_t type;
    size_t size = sizeof(type);
    sysctlbyname("hw.cputype", &type, &size, NULL, 0);

    int procTranslated;
    size = sizeof(procTranslated);
    // Checks whether process is translated by Rosetta
    sysctlbyname("sysctl.proc_translated", &procTranslated, &size, NULL, 0);

    // Removes CPU_ARCH_ABI64 or CPU_ARCH_ABI64_32 encoded with the Type
    cpu_type_t typeWithABIInfoRemoved = type & ~CPU_ARCH_MASK;

    if (typeWithABIInfoRemoved == CPU_TYPE_X86)
    {
        if (procTranslated == 1)
        {
            cout << "ARM Processor (Running x86 application in Rosetta)";
        }
        else
        {
            cout << "Intel Processor";
        }
    }
    else if (typeWithABIInfoRemoved == CPU_TYPE_ARM)
    {
        cout << "ARM Processor";
    }
}
Woothen answered 7/6, 2022 at 5:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.