1# Based on the Qt 5 processor detection code, so should be very accurate
2# https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qprocessordetection.h
3# Currently handles ARM (v5, v6, v7, v8), ARM64, x86 (32/64), ia64, and ppc (32/64)
4
5# Regarding POWER/PowerPC, just as is noted in the Qt source,
6# "There are many more known variants/revisions that we do not handle/detect."
7
8set(archdetect_c_code "
9#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__)
10  #if defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64)
11    #error cmake_ARCH ARM64
12  #else
13    #error cmake_ARCH ARM
14  #endif
15#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
16    #error cmake_ARCH x64
17#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
18    #error cmake_ARCH ia64
19#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
20    #error cmake_ARCH x86
21#else
22	#error cmake_ARCH unknown
23#endif
24")
25
26# Set ppc_support to TRUE before including this file or ppc and ppc64
27# will be treated as invalid architectures since they are no longer supported by Apple
28
29message (STATUS ${CMAKE_GENERATOR})
30
31function(get_target_architecture output_var)
32	if (MSVC AND (${CMAKE_GENERATOR} MATCHES "X64$"))
33		set (ARCH x64)
34
35	elseif (MSVC AND (${CMAKE_GENERATOR} MATCHES "ARM$"))
36		set (ARCH ARM)
37
38    elseif (MSVC AND (${CMAKE_GENERATOR} MATCHES "ARM64$"))
39		set (ARCH ARM64)
40
41    else()
42        file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
43
44        enable_language(C)
45
46        # Detect the architecture in a rather creative way...
47        # This compiles a small C program which is a series of ifdefs that selects a
48        # particular #error preprocessor directive whose message string contains the
49        # target architecture. The program will always fail to compile (both because
50        # file is not a valid C program, and obviously because of the presence of the
51        # #error preprocessor directives... but by exploiting the preprocessor in this
52        # way, we can detect the correct target architecture even when cross-compiling,
53        # since the program itself never needs to be run (only the compiler/preprocessor)
54        try_run(
55            run_result_unused
56            compile_result_unused
57            "${CMAKE_BINARY_DIR}"
58            "${CMAKE_BINARY_DIR}/arch.c"
59            COMPILE_OUTPUT_VARIABLE ARCH
60        )
61
62        # Parse the architecture name from the compiler output
63        string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
64
65        # Get rid of the value marker leaving just the architecture name
66        string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
67
68        # If we are compiling with an unknown architecture this variable should
69        # already be set to "unknown" but in the case that it's empty (i.e. due
70        # to a typo in the code), then set it to unknown
71        if (NOT ARCH AND MSVC)
72			set (ARCH x86)
73        endif()
74    endif()
75
76    set(${output_var} "${ARCH}" PARENT_SCOPE)
77endfunction()
78