124

What is the most reliable way to find out CPU architecture when compiling C or C++ code? As far as I can tell, different compilers have their own set of non-standard preprocessor definitions (_M_X86 in MSVS, __i386__, __arm__ in GCC, etc).

Is there a standard way to detect the architecture I'm building for? If not, is there a source for a comprehensive list of such definitions for various compilers, such as a header with all the boilerplate #ifdefs?

2

8 Answers 8

53

Enjoy, I was the original author of this.

extern "C" {
    const char *getBuild() { //Get current architecture, detectx nearly every architecture. Coded by Freak
        #if defined(__x86_64__) || defined(_M_X64)
        return "x86_64";
        #elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86)
        return "x86_32";
        #elif defined(__ARM_ARCH_2__)
        return "ARM2";
        #elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__)
        return "ARM3";
        #elif defined(__ARM_ARCH_4T__) || defined(__TARGET_ARM_4T)
        return "ARM4T";
        #elif defined(__ARM_ARCH_5_) || defined(__ARM_ARCH_5E_)
        return "ARM5"
        #elif defined(__ARM_ARCH_6T2_) || defined(__ARM_ARCH_6T2_)
        return "ARM6T2";
        #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
        return "ARM6";
        #elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
        return "ARM7";
        #elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
        return "ARM7A";
        #elif defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
        return "ARM7R";
        #elif defined(__ARM_ARCH_7M__)
        return "ARM7M";
        #elif defined(__ARM_ARCH_7S__)
        return "ARM7S";
        #elif defined(__aarch64__) || defined(_M_ARM64)
        return "ARM64";
        #elif defined(mips) || defined(__mips__) || defined(__mips)
        return "MIPS";
        #elif defined(__sh__)
        return "SUPERH";
        #elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
        return "POWERPC";
        #elif defined(__PPC64__) || defined(__ppc64__) || defined(_ARCH_PPC64)
        return "POWERPC64";
        #elif defined(__sparc__) || defined(__sparc)
        return "SPARC";
        #elif defined(__m68k__)
        return "M68K";
        #else
        return "UNKNOWN";
        #endif
    }
}
Sign up to request clarification or add additional context in comments.

8 Comments

Your ARM strings are mixing up ARM CPU names like ARM7 with ARM ISA revisions like ARMv7.
updated the post with correct arm7 versions. as well as powerpc64 detection proper
I meant that you return "ARM7" when you should be returning "ARMv7", or "ARMv7A" or whatever. The "v" is important in ARM in telling the difference between a specific ARM core model vs. an ISA version. Remember that someone looking at a program that prints this string will just the see one string on their machine, not the whole table that makes it clear it could have been "ARM6T2" (which is more clearly just a corruption of ARMv6T2, not a CPU model number.)
Is there a simpler way to detect 32-bit ARM?
Consider adding support for RISC-V. It seems that the correct macros are: __riscv, __riscv32, __riscv__, _riscv (found here).
|
22

If you would like to dump all available features on a particular platform, you could run GCC like:

gcc -march=native -dM -E - </dev/null

It would dump macros like #define __SSE3__ 1, #define __AES__ 1, etc.

5 Comments

-march=native fails for ARM and MIPS for GCC 4.9 and below.
The question was at compile time -- this doesn't answer that
@Walter if one has access to the architecture in question, it allows them to inspect which macros are actually defined, and then use them in the code so that it does work at compile time.
You should also use the -xc++ switch to specify what you are compiling (C vs C++).
This is what I needed! I didn't I'm trying to make something compile on PPC64 and didn't know what gcc exposed. I had to use -mcpu=native, but now I know it's __powerpc__ and __powerpc64__
21

There's no inter-compiler standard, but each compiler tends to be quite consistent. You can build a header for yourself that's something like this:

#if MSVC
#ifdef _M_X86
#define ARCH_X86
#endif
#endif

#if GCC
#ifdef __i386__
#define ARCH_X86
#endif
#endif

There's not much point to a comprehensive list, because there are thousands of compilers but only 3-4 in widespread use (Microsoft C++, GCC, Intel CC, maybe TenDRA?). Just decide which compilers your application will support, list their #defines, and update your header as needed.

3 Comments

This did not work for me on Visual Studio 2010. _M_X86 was positively not defined (32-bit build). The correct one is _M_IX86 (credit to Serge's link above).
Do these work on both 32-bit and 64-bit x86?
... and clang/LLVM. Also on architectures other than x86 for embedded systems there are a few others in common use.
14

If you want a cross-compiler solution then just use Boost.Predef which contains

  • BOOST_ARCH_ for system/CPU architecture one is compiling for.
  • BOOST_COMP_ for the compiler one is using.
  • BOOST_LANG_ for language standards one is compiling against.
  • BOOST_LIB_C_ and BOOST_LIB_STD_ for the C and C++ standard library in use.
  • BOOST_OS_ for the operating system we are compiling to.
  • BOOST_PLAT_ for platforms on top of operating system or compilers.
  • BOOST_ENDIAN_ for endianness of the os and architecture combination.
  • BOOST_HW_ for hardware specific features.
  • BOOST_HW_SIMD for SIMD (Single Instruction Multiple Data) detection.

Note that although Boost is usually thought of as a C++ library, Boost.Predef is pure header-only and works for C

For example

#include <boost/predef.h>
// or just include the necessary headers
// #include <boost/predef/architecture.h>
// #include <boost/predef/other.h>

#if BOOST_ARCH_X86
    #if BOOST_ARCH_X86_64
            std::cout << "x86-64\n";
    #elif BOOST_ARCH_X86_32
            std::cout << "x86-32\n";
    #else
            std::cout << "x86-" << BOOST_ARCH_WORD_BITS << '\n'; // Probably x86-16
    #endif
#elif BOOST_ARCH_ARM
    #if BOOST_ARCH_ARM >= BOOST_VERSION_NUMBER(8, 0, 0)
        #if BOOST_ARCH_WORD_BITS == 64
            std::cout << "ARMv8+ Aarch64\n";
        #elif BOOST_ARCH_WORD_BITS == 32
            std::cout << "ARMv8+ Aarch32\n";
        #else
            std::cout << "Unexpected ARMv8+ " << BOOST_ARCH_WORD_BITS << "bit\n";
        #endif
    #elif BOOST_ARCH_ARM >= BOOST_VERSION_NUMBER(7, 0, 0)
            std::cout << "ARMv7 (ARM32)\n";
    #elif BOOST_ARCH_ARM >= BOOST_VERSION_NUMBER(6, 0, 0)
            std::cout << "ARMv6 (ARM32)\n";
    #else
            std::cout << "ARMv5 or older\n";
    #endif
#elif BOOST_ARCH_MIPS
    #if BOOST_ARCH_WORD_BITS == 64
            std::cout << "MIPS64\n";
    #else
            std::cout << "MIPS32\n";
    #endif
#elif BOOST_ARCH_PPC_64
            std::cout << "PPC64\n";
#elif BOOST_ARCH_PPC
            std::cout << "PPC32\n";
#else
            std::cout << "Unknown " << BOOST_ARCH_WORD_BITS << "-bit arch\n";
#endif

You can find out more on how to use it here

Demo on Godbolt

2 Comments

Does this mean that _M_ARM is only defined on 32-bit ARM?
@AaronFranke no, that was my mistake because the documentation was unclear. Please see my update. You can check ARM32 easily with BOOST_ARCH_WORD_BITS
4

There's a list of the #defines here. There was a previous highly voted answer that included this link but it was deleted by a mod presumably due to SO's "answers must have code" rule. So here's a random sample. Follow the link for the full list.

AMD64

Type Macro Description
Identification __amd64__ __amd64 __x86_64__ __x86_64 Defined by GNU C and Sun Studio
Identification _M_X64 _M_AMD64 Defined by Visual Studio

2 Comments

What about for 32-bit? What's the shortest way I can detect both 32-bit and 64-bit x86 that works in MSVC, GCC, and Clang?
You can use a combination of the AMD64 and Intel x86 macros listed on that page. But you almost certainly shouldn't. Use sizeof(), static_assert and so on instead. Also you should be aware of the x32 ABI. Even on a 64-bit architecture pointers can be 32-bit.
4

There's nothing standard. Brian Hook documented a bunch of these in his "Portable Open Source Harness", and even tries to make them into something coherent and usable (ymmv regarding that). See the posh.h header on his repo:

3 Comments

Jeez - sorry about the bogus link - it should be to hookatooka.com/poshlib that gives information about the userid/password. My browser must have 'auto logged in' from some previous visit to the page.
Its also worth noting... The authors of the website stated why they did added a password: "I apologize for the inconvenience, but due to an inexplicable DDoS attack on our earlier direct link, we've had to create this page to 'buffer' against the DDoS..." I'm not sure its fair to penalize Michael for it.
None of the links work. Could you please update it? Thanks!
1

My spin at it

Usage

#if ARCHITECTURE_ARM
    ...
#endif

File arm.h

#ifndef ARCHITECTURE_ARM_H
#define ARCHITECTURE_ARM_H

/*
    from:
        https://github.com/boostorg/predef/blob/develop/include/boost/predef/architecture/arm.h
        https://github.com/cpredef/predef/blob/master/Architectures.md
        https://wiki.ubuntu.com/ARM/Thumb2PortingHowto

    __arm__             |   Defined by GNU C and RealView
    __thumb__           |   Defined by GNU C and RealView in Thumb mode
    __TARGET_ARCH_ARM   |   Defined by RealView
    __TARGET_ARCH_THUMB |   Defined by RealView
    _ARM                |   Defined by ImageCraft C
    _M_ARM              |   Defined by Visual Studio
    _M_ARMT             |   Defined by Visual Studio in Thumb mode
    __arm               |   Defined by Diab

    ARM 2   |   __ARM_ARCH_2__  
    ARM 3   |   __ARM_ARCH_3__, __ARM_ARCH_3M__
    ARM 4   |   __ARM_ARCH_4__
    ARM 4T  |   __ARM_ARCH_4T__, __TARGET_ARM_4T
    ARM 5   |   __ARM_ARCH_5__, __ARM_ARCH_5E__
    ARM 5T  |   __ARM_ARCH_5T__, __ARM_ARCH_5TE__, __ARM_ARCH_5TEJ__    
    ARM 6   |   __ARM_ARCH_6__, __ARM_ARCH_6J__, __ARM_ARCH_6K__, __ARM_ARCH_6Z__, __ARM_ARCH_6ZK__
    ARM 6T2 |   __ARM_ARCH_6T2__    
    ARM 7   |   __ARM_ARCH_7__, __ARM_ARCH_7A__, __ARM_ARCH_7R__, __ARM_ARCH_7M__, __ARM_ARCH_7S__
    ARM 2   |   __ARM_ARCH_2__  
    ARM 3   |   __ARM_ARCH_3__, __ARM_ARCH_3M__ 
    ARM 4T  |   __ARM_ARCH_4T__, __TARGET_ARM_4T
    ARM 5   |   __ARM_ARCH_5__, __ARM_ARCH_5E__
    ARM 5T  |   __ARM_ARCH_5T__,__ARM_ARCH_5TE__,__ARM_ARCH_5TEJ__  
    ARM 6   |   __ARM_ARCH_6__, __ARM_ARCH_6J__, __ARM_ARCH_6K__, __ARM_ARCH_6Z__, __ARM_ARCH_6ZK__
    ARM 6T2 |   __ARM_ARCH_6T2__    
    ARM 7   |   __ARM_ARCH_7__, __ARM_ARCH_7A__, __ARM_ARCH_7R__, __ARM_ARCH_7M__, __ARM_ARCH_7S__
*/


#if defined(__ARM_ARCH_2__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_2 1

#elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_3 1

#elif defined(__ARM_ARCH_4__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_4 1

#elif defined(__ARM_ARCH_4T__) || defined(__TARGET_ARM_4T)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_4T 1

#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5E__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_5 1

#elif defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_5T 1

#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_6 1

#elif defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6T2__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_6T2 1

#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_7 1

#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_7A 1

#elif defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_7R 1

#elif defined(__ARM_ARCH_7M__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_7M 1

#elif defined(__ARM_ARCH_7S__)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_7S 1

#elif defined(__aarch64__) || defined(_M_ARM64) || defined(__AARCH64EL__) || defined(__arm64)
#   define ARCHITECTURE_ARM 1
#   define ARCHITECTURE_ARM_64 1

#elif defined(__arm__) || defined(__thumb__) || defined(__TARGET_ARCH_ARM) || defined(__TARGET_ARCH_THUMB) || defined(__ARM) || defined(_M_ARM) || defined(_M_ARM_T) || defined(__ARM_ARCH)
#   define ARCHITECTURE_ARM 1

#endif

#endif /* ARCHITECTURE_ARM_H */

File x86_64.h

#ifndef ARCHITECTURE_X86_64_H
#define ARCHITECTURE_X86_64_H

/*
    from:
        https://github.com/cpredef/predef/blob/master/Architectures.md
        https://github.com/boostorg/predef/blob/develop/include/boost/predef/architecture/x86/64.h

    __amd64__, __amd64, __x86_64__, __x86_64    |   Defined by GNU C and Sun Studio
    _M_X64, _M_AMD64                            |   Defined by Visual C++
*/

#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || defined(__amd64) || defined(_M_X64) || defined(_M_AMD64)
#   define ARCHITECTURE_X86_64

#endif

#endif /* ARCHITECTURE_X86_64_H */

File x86_32.h

#ifndef ARCHITECTURE_X86_32_H
#define ARCHITECTURE_X86_32_H

/*
    from:
        https://github.com/cpredef/predef/blob/master/Architectures.md
        https://github.com/boostorg/predef/blob/develop/include/boost/predef/architecture/x86/32.h


    i386, __i386, __i386__, __i486__, __i586__, __i686__    | Defined by GNU C
    __i386                                                  | Defined by Sun Studio
    __i386, __IA32__                                        | Defined by Stratus VOS C
    _M_I86                                                  | Only defined for 16-bits architectures. Defined by Visual C++, Digital Mars, and Watcom C/C++ (see note below)
    _M_IX86                                                 | Only defined for 32-bits architectures. Defined by Visual C++, Intel C/C++, Digital Mars, and Watcom C/C++
    __X86__                                                 | Defined by Watcom C/C++
    _X86_                                                   | Defined by MinGW32
    __THW_INTEL__                                           | Defined by XL C/C++
    __I86__                                                 | Defined by Digital Mars
    __INTEL__                                               | Defined by CodeWarrior
    __386                                                   | Defined by Diab
*/

#if defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__IA32__)|| defined(_M_I86) || defined(_M_IX86)|| defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || defined(__386)
#    define ARCHITECTURE_X86_32 1

#endif

#endif /* ARCHITECTURE_X86_32_H */

Comments

-4

If you need a fine-grained detection of CPU features, the best approach is to ship also a CPUID program which outputs to stdout or some "cpu_config.h" file the set of features supported by the CPU. Then you integrate that program with your build process.

1 Comment

Will not work for cross compiling. And how do you compile a cpuid program unless you know which machine it needs to run on?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.