From 44ccefb28af6167794dd3ed19cb2f18a803b2500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Hrdli=C4=8Dka?= Date: Sun, 29 Aug 2021 03:37:07 +0200 Subject: [PATCH] cmake: refactor the architecture detection --- CMakeLists.txt | 14 ++-- cmake/TargetArch.cmake | 141 --------------------------------- src/CMakeLists.txt | 2 +- src/arch_detect.c | 27 +++++++ src/codegen/CMakeLists.txt | 7 +- src/codegen_new/CMakeLists.txt | 11 ++- 6 files changed, 45 insertions(+), 157 deletions(-) delete mode 100644 cmake/TargetArch.cmake create mode 100644 src/arch_detect.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5507570fa..410db2af8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,9 +24,13 @@ project(86Box HOMEPAGE_URL "https://86box.github.io/" LANGUAGES C CXX) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -include(TargetArch) -target_architecture(CMAKE_TARGET_ARCHITECTURES) +# Detect the target architecture by trying to compile `src/arch_detect.c` +try_compile(RESULT_VAR ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/src/arch_detect.c" OUTPUT_VARIABLE ARCH) +string(REGEX MATCH "ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}") +string(REPLACE "ARCH " "" ARCH "${ARCH}") +if (NOT ARCH) + set(ARCH unknown) +endif() include(CPack) @@ -83,12 +87,12 @@ CMAKE_DEPENDENT_OPTION(XL24 "ATI VGA Wonder XL24 (ATI-28800-6)" ON "DEV_BRANCH" CMAKE_DEPENDENT_OPTION(VECT486VL "HP Vectra 486VL" ON "DEV_BRANCH" OFF) # HACK: Avoid a MSVC2019 compiler bug on ARM64 Debug builds -if(MSVC_TOOLSET_VERSION GREATER_EQUAL 142 AND CMAKE_TARGET_ARCHITECTURES STREQUAL "armv8") +if(MSVC_TOOLSET_VERSION GREATER_EQUAL 142 AND ARCH STREQUAL "arm64") # Define a cache option in case somebody wants to disable this workaround set(AVOID_LNK1322 ON CACHE BOOL "Prevent LNK1322 on MSVC2019 ARM64 debug builds") if(AVOID_LNK1322) - message(STATUS "Working around LNK1322 (#1268)") + message(STATUS "Working around LNK1322 (86Box#1268)") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Gy") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Gy") endif() diff --git a/cmake/TargetArch.cmake b/cmake/TargetArch.cmake deleted file mode 100644 index c8eb27735..000000000 --- a/cmake/TargetArch.cmake +++ /dev/null @@ -1,141 +0,0 @@ -# Based on the Qt 5 processor detection code, so should be very accurate -# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h -# Currently handles arm (v5, v6, v7, v8), x86 (32/64), ia64, and ppc (32/64) - -# Regarding POWER/PowerPC, just as is noted in the Qt source, -# "There are many more known variants/revisions that we do not handle/detect." - -set(archdetect_c_code " -#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(_M_ARM64) - #if defined(__ARM64_ARCH_8__) \\ - || defined(__aarch64__) \\ - || defined(__ARMv8__) \\ - || defined(__ARMv8_A__) \\ - || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8) \\ - || (defined(_M_ARM64) && _M_ARM64 >= 1) - #error cmake_ARCH armv8 - #elif defined(__ARM_ARCH_7__) \\ - || defined(__ARM_ARCH_7A__) \\ - || defined(__ARM_ARCH_7R__) \\ - || defined(__ARM_ARCH_7M__) \\ - || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7) \\ - || (defined(_M_ARM) && _M_ARM >= 7) - #error cmake_ARCH armv7 - #elif defined(__ARM_ARCH_6__) \\ - || defined(__ARM_ARCH_6J__) \\ - || defined(__ARM_ARCH_6T2__) \\ - || defined(__ARM_ARCH_6Z__) \\ - || defined(__ARM_ARCH_6K__) \\ - || defined(__ARM_ARCH_6ZK__) \\ - || defined(__ARM_ARCH_6M__) \\ - || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6) - #error cmake_ARCH armv6 - #elif defined(__ARM_ARCH_5TEJ__) \\ - || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5) - #error cmake_ARCH armv5 - #else - #error cmake_ARCH arm - #endif -#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) - #error cmake_ARCH i386 -#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) - #error cmake_ARCH x86_64 -#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) - #error cmake_ARCH ia64 -#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\ - || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\ - || defined(_M_MPPC) || defined(_M_PPC) - #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__) - #error cmake_ARCH ppc64 - #else - #error cmake_ARCH ppc - #endif -#endif -#error cmake_ARCH unknown -") - -# Set ppc_support to TRUE before including this file or ppc and ppc64 -# will be treated as invalid architectures since they are no longer supported by Apple - -function(target_architecture output_var) - if(APPLE AND CMAKE_OSX_ARCHITECTURES) - # On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set - # First let's normalize the order of the values - - # Note that it's not possible to compile PowerPC applications if you are using - # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we - # disable it by default - # See this page for more information: - # http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4 - - # Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime. - # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise. - - foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES}) - if("${osx_arch}" STREQUAL "ppc" AND ppc_support) - set(osx_arch_ppc TRUE) - elseif("${osx_arch}" STREQUAL "i386") - set(osx_arch_i386 TRUE) - elseif("${osx_arch}" STREQUAL "x86_64") - set(osx_arch_x86_64 TRUE) - elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support) - set(osx_arch_ppc64 TRUE) - else() - message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}") - endif() - endforeach() - - # Now add all the architectures in our normalized order - if(osx_arch_ppc) - list(APPEND ARCH ppc) - endif() - - if(osx_arch_i386) - list(APPEND ARCH i386) - endif() - - if(osx_arch_x86_64) - list(APPEND ARCH x86_64) - endif() - - if(osx_arch_ppc64) - list(APPEND ARCH ppc64) - endif() - else() - file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}") - - enable_language(C) - - # Detect the architecture in a rather creative way... - # This compiles a small C program which is a series of ifdefs that selects a - # particular #error preprocessor directive whose message string contains the - # target architecture. The program will always fail to compile (both because - # file is not a valid C program, and obviously because of the presence of the - # #error preprocessor directives... but by exploiting the preprocessor in this - # way, we can detect the correct target architecture even when cross-compiling, - # since the program itself never needs to be run (only the compiler/preprocessor) - try_run( - run_result_unused - compile_result_unused - "${CMAKE_BINARY_DIR}" - "${CMAKE_BINARY_DIR}/arch.c" - COMPILE_OUTPUT_VARIABLE ARCH - CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} - ) - - # Parse the architecture name from the compiler output - string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}") - - # Get rid of the value marker leaving just the architecture name - string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}") - - # If we are compiling with an unknown architecture this variable should - # already be set to "unknown" but in the case that it's empty (i.e. due - # to a typo in the code), then set it to unknown - if (NOT ARCH) - set(ARCH unknown) - endif() - endif() - - set(${output_var} "${ARCH}" PARENT_SCOPE) -endfunction() \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1f4b9c7c..dc7f76dd0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,7 +62,7 @@ find_package(PNG REQUIRED) include_directories(${PNG_INCLUDE_DIRS}) target_link_libraries(86Box PNG::PNG) -if(CMAKE_TARGET_ARCHITECTURES STREQUAL "i386") +if(ARCH STREQUAL "i386") if(MSVC) set_target_properties(86Box PROPERTIES LINK_FLAGS "/LARGEADDRESSAWARE") elseif(MINGW) diff --git a/src/arch_detect.c b/src/arch_detect.c new file mode 100644 index 000000000..03d3b61e7 --- /dev/null +++ b/src/arch_detect.c @@ -0,0 +1,27 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Configure-time architecture detection for the CMake build. + * + * + * + * Authors: David Hrdlička, + * + * Copyright 2020-2021 David Hrdlička. + */ + +#if defined(__arm__) || defined(__TARGET_ARCH_ARM) + #error ARCH arm +#elif defined(__aarch64__) || defined(_M_ARM64) + #error ARCH arm64 +#elif defined(__i386) || defined(__i386__) || defined(_M_IX86) + #error ARCH i386 +#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) + #error ARCH x86_64 +#endif +#error ARCH unknown diff --git a/src/codegen/CMakeLists.txt b/src/codegen/CMakeLists.txt index 7ee69bf3b..1d310c0de 100644 --- a/src/codegen/CMakeLists.txt +++ b/src/codegen/CMakeLists.txt @@ -16,16 +16,15 @@ if(DYNAREC) add_library(dynarec OBJECT codegen.c codegen_ops.c) - if(CMAKE_TARGET_ARCHITECTURES STREQUAL "i386") + if(ARCH STREQUAL "i386") target_sources(dynarec PRIVATE codegen_x86.c codegen_accumulate_x86.c) - elseif(CMAKE_TARGET_ARCHITECTURES STREQUAL "x86_64") + elseif(ARCH STREQUAL "x86_64") target_sources(dynarec PRIVATE codegen_x86-64.c codegen_accumulate_x86-64.c) else() message(SEND_ERROR - "Dynarec is incompatible with target platform " - ${CMAKE_TARGET_ARCHITECTURES}) + "Dynarec is incompatible with target platform ${ARCH}") endif() target_link_libraries(86Box dynarec cgt) diff --git a/src/codegen_new/CMakeLists.txt b/src/codegen_new/CMakeLists.txt index 0a6db2827..15f1874f8 100644 --- a/src/codegen_new/CMakeLists.txt +++ b/src/codegen_new/CMakeLists.txt @@ -25,27 +25,26 @@ if(DYNAREC) codegen_ops_mmx_pack.c codegen_ops_mmx_shift.c codegen_ops_mov.c codegen_ops_shift.c codegen_ops_stack.c codegen_reg.c) - if(CMAKE_TARGET_ARCHITECTURES STREQUAL "i386") + if(ARCH STREQUAL "i386") target_sources(dynarec PRIVATE codegen_backend_x86.c codegen_backend_x86_ops.c codegen_backend_x86_ops_fpu.c codegen_backend_x86_ops_sse.c codegen_backend_x86_uops.c) - elseif(CMAKE_TARGET_ARCHITECTURES STREQUAL "x86_64") + elseif(ARCH STREQUAL "x86_64") target_sources(dynarec PRIVATE codegen_backend_x86-64.c codegen_backend_x86-64_ops.c codegen_backend_x86-64_ops_sse.c codegen_backend_x86-64_uops.c) - elseif(CMAKE_TARGET_ARCHITECTURES STREQUAL "armv8") + elseif(ARCH STREQUAL "arm64") target_sources(dynarec PRIVATE codegen_backend_arm64.c codegen_backend_arm64_ops.c codegen_backend_arm64_uops.c codegen_backend_arm64_imm.c) - elseif(CMAKE_TARGET_ARCHITECTURES MATCHES "arm") + elseif(ARCH STREQUAL "arm") target_sources(dynarec PRIVATE codegen_backend_arm.c codegen_backend_arm_ops.c codegen_backend_arm_uops.c) else() message(SEND_ERROR - "Dynarec is incompatible with target platform " - ${CMAKE_TARGET_ARCHITECTURES}) + "Dynarec is incompatible with target platform ${ARCH}") endif() target_link_libraries(86Box dynarec cgt)