# SPDX-FileCopyrightText: 2025 crueter # SPDX-License-Identifier: GPL-3.0-or-later ## DetectArchitecture ## #[[ Does exactly as it sounds. Detects common symbols defined for different architectures and adds compile definitions thereof. Namely: - arm64 - arm - x86_64 - x86 - ia64 - mips64 - mips - ppc64 - ppc - riscv - riscv64 - loongarch64 - wasm Unsupported architectures: - ARMv2-6 - m68k - PIC This file WILL NOT detect endian-ness for you. This file is based off of Yuzu and Dynarmic. ]] # multiarch builds are a special case and also very difficult # this is what I have for now, but it's not ideal # Do note that situations where multiple architectures are defined # should NOT be too dependent on the architecture # otherwise, you may end up with duplicate code if (CMAKE_OSX_ARCHITECTURES) set(MULTIARCH_BUILD 1) set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}") # hope and pray the architecture names match foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES}) set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE) add_definitions(-DARCHITECTURE_${ARCH}=1) endforeach() return() endif() include(CheckSymbolExists) function(detect_architecture symbol arch) # The output variable needs to be unset between invocations otherwise # CMake's crazy scope rules will keep it defined unset(SYMBOL_EXISTS CACHE) if (NOT DEFINED ARCHITECTURE) set(CMAKE_REQUIRED_QUIET 1) check_symbol_exists("${symbol}" "" SYMBOL_EXISTS) unset(CMAKE_REQUIRED_QUIET) if (SYMBOL_EXISTS) set(ARCHITECTURE "${arch}" PARENT_SCOPE) set(ARCHITECTURE_${arch} 1 PARENT_SCOPE) add_definitions(-DARCHITECTURE_${arch}=1) endif() endif() endfunction() function(detect_architecture_symbols) if (DEFINED ARCHITECTURE) return() endif() set(oneValueArgs ARCH) set(multiValueArgs SYMBOLS) cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}") set(arch "${ARGS_ARCH}") foreach(symbol ${ARGS_SYMBOLS}) detect_architecture("${symbol}" "${arch}") if (ARCHITECTURE_${arch}) message(DEBUG "[DetectArchitecture] Found architecture symbol ${symbol} for ${arch}") set(ARCHITECTURE "${arch}" PARENT_SCOPE) set(ARCHITECTURE_${arch} 1 PARENT_SCOPE) add_definitions(-DARCHITECTURE_${arch}=1) return() endif() endforeach() endfunction() function(DetectArchitecture) # arches here are put in a sane default order of importance # notably, amd64, arm64, and riscv (in order) are BY FAR the most common # mips is pretty popular in embedded # ppc64 is pretty popular in supercomputing # sparc is uh # ia64 exists # the rest exist, but are probably less popular than ia64 detect_architecture_symbols( ARCH arm64 SYMBOLS "__ARM64__" "__aarch64__" "_M_ARM64") detect_architecture_symbols( ARCH x86_64 SYMBOLS "__x86_64" "__x86_64__" "__amd64" "_M_X64" "_M_AMD64") # riscv is interesting since it generally does not define a riscv64-specific symbol # We can, however, check for the rv32 zcf extension which is good enough of a heuristic on GCC detect_architecture_symbols( ARCH riscv SYMBOLS "__riscv_zcf") # if zcf doesn't exist we can safely assume it's riscv64 detect_architecture_symbols( ARCH riscv64 SYMBOLS "__riscv") detect_architecture_symbols( ARCH x86 SYMBOLS "__i386" "__i386__" "_M_IX86") detect_architecture_symbols( ARCH arm SYMBOLS "__arm__" "__TARGET_ARCH_ARM" "_M_ARM") detect_architecture_symbols( ARCH ia64 SYMBOLS "__ia64" "__ia64__" "_M_IA64") # mips is probably the least fun to detect due to microMIPS # Because microMIPS is such cancer I'm considering it out of scope for now detect_architecture_symbols( ARCH mips64 SYMBOLS "__mips64") detect_architecture_symbols( ARCH mips SYMBOLS "__mips" "__mips__" "_M_MRX000") detect_architecture_symbols( ARCH ppc64 SYMBOLS "__ppc64__" "__powerpc64__" "_ARCH_PPC64" "_M_PPC64") detect_architecture_symbols( ARCH ppc SYMBOLS "__ppc__" "__ppc" "__powerpc__" "_ARCH_COM" "_ARCH_PWR" "_ARCH_PPC" "_M_MPPC" "_M_PPC") detect_architecture_symbols( ARCH sparc64 SYMBOLS "__sparc_v9__") detect_architecture_symbols( ARCH sparc SYMBOLS "__sparc__" "__sparc") # I don't actually know about loongarch32 since crossdev does not support it, only 64 detect_architecture_symbols( ARCH loongarch64 SYMBOLS "__loongarch__" "__loongarch64") detect_architecture_symbols( ARCH wasm SYMBOLS "__EMSCRIPTEN__") # "generic" target # If you have reached this point, you're on some as-of-yet unsupported architecture. # See the docs up above for known unsupported architectures # If you're not in the list... I think you know what you're doing. if (NOT DEFINED ARCHITECTURE) set(ARCHITECTURE "GENERIC") set(ARCHITECTURE_GENERIC 1) add_definitions(-DARCHITECTURE_GENERIC=1) endif() message(STATUS "[DetectArchitecture] Target architecture: ${ARCHITECTURE}") set(ARCHITECTURE "${ARCHITECTURE}" PARENT_SCOPE) set(ARCHITECTURE_${ARCHITECTURE} 1 PARENT_SCOPE) endfunction()