Reputation: 84962
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 #ifdef
s?
Upvotes: 123
Views: 110619
Reputation: 2415
My spin at it
#if ARCHITECTURE_ARM
...
#endif
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 */
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 */
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 */
Upvotes: 1
Reputation: 340496
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:
Upvotes: 4
Reputation: 42012
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
Upvotes: 14
Reputation: 97058
There's a list of the #define
s 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.
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 |
Upvotes: 4
Reputation: 619
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
}
}
Upvotes: 51
Reputation: 2194
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.
Upvotes: 20
Reputation: 24584
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.
Upvotes: -4
Reputation: 200996
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.
Upvotes: 21