diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f4a215413..a349fff0a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,13 @@ if (Daemon_OUT) endif() include(Yokai/All) -include(DaemonNaclHost) + +include(DaemonNaclArchitecture) + +daemon_detect_nacl_arch("${YOKAI_TARGET_ARCH_NAME}") + +# Add printable strings to the executable. +yokai_add_buildinfo("char*" "DAEMON_NACL_ARCH_STRING" "\"${DAEMON_NACL_ARCH_NAME}\"") ################################################################################ # Configuration options @@ -190,7 +196,7 @@ else() endif() # Dependencies version, this must match the number in external_deps/build.sh -set(DEPS_VERSION 11) +set(DEPS_VERSION 12) option(USE_EXTERNAL_DEPS "Download or reuse dependencies from EXTERNAL_DEPS_DIR (mandatory for building and running NaCl .nexe binaries)." ON) @@ -220,17 +226,7 @@ if (USE_EXTERNAL_DEPS AND NOT YOKAI_TARGET_SYSTEM_NACL) set(SUPPORTED_${DEPS_SYSTEM}_ARCH amd64 i686) elseif (YOKAI_TARGET_SYSTEM_MACOS) set(DEPS_SYSTEM macos) - set(SUPPORTED_${DEPS_SYSTEM}_ARCH amd64) - - if (YOKAI_TARGET_ARCH_ARM64) - set(DEPS_ARCH amd64) - - set_deps_dir() - - if (NOT EXISTS ${DEPS_DIR}) - set(DEFAULT_USE_EXTERNAL_DEPS_LIBS OFF) - endif() - endif() + set(SUPPORTED_${DEPS_SYSTEM}_ARCH amd64 arm64) elseif (YOKAI_TARGET_SYSTEM_LINUX) set(DEPS_SYSTEM linux) set(SUPPORTED_${DEPS_SYSTEM}_ARCH amd64 i686 arm64 armhf) @@ -970,56 +966,55 @@ if (DEPS_DIR AND HAS_NACL AND (BUILD_CLIENT OR BUILD_TTY_CLIENT OR BUILD_SERVER add_custom_target(runtime_deps) set_target_properties(runtime_deps PROPERTIES FOLDER "CMakePlumbing") - # The NaCl loader and IRT are required to load .nexe files - add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${DEPS_DIR}/nacl_loader${CMAKE_EXECUTABLE_SUFFIX} - ${FULL_OUTPUT_DIR}/nacl_loader${CMAKE_EXECUTABLE_SUFFIX} - ) + foreach(arch_name IN LISTS DAEMON_NACL_ARCH_NAME_LIST) + # The NaCl loader and IRT are required to load .nexe files + add_custom_command(TARGET runtime_deps PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${DEPS_DIR}/nacl_loader-${arch_name}${CMAKE_EXECUTABLE_SUFFIX} + ${FULL_OUTPUT_DIR}/nacl_loader-${arch_name}${CMAKE_EXECUTABLE_SUFFIX} + ) - add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${DEPS_DIR}/irt_core-${DAEMON_NACL_ARCH_NAME}.nexe - ${FULL_OUTPUT_DIR}/irt_core-${DAEMON_NACL_ARCH_NAME}.nexe - ) + add_custom_command(TARGET runtime_deps PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${DEPS_DIR}/irt_core-${arch_name}.nexe + ${FULL_OUTPUT_DIR}/irt_core-${arch_name}.nexe + ) + endforeach() # Linux uses a bootstrap program to reserve address space if (YOKAI_TARGET_SYSTEM_LINUX_COMPATIBILITY) if (YOKAI_TARGET_ARCH_ARM64) - add_executable(nacl_helper_bootstrap-armhf tools/nacl_helper_bootstrap-armhf/nacl_helper_bootstrap-armhf.cpp) - add_dependencies(runtime_deps nacl_helper_bootstrap-armhf) + add_executable(nacl_helper_bootstrap-ldarmhf tools/nacl_helper_bootstrap-ldarmhf/nacl_helper_bootstrap-ldarmhf.cpp) + add_dependencies(runtime_deps nacl_helper_bootstrap-ldarmhf) add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - ${FULL_OUTPUT_DIR}/lib-armhf + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${DEPS_DIR}/libs-linux-armhf + ${FULL_OUTPUT_DIR}/libs-linux-armhf ) + endif() + foreach(arch_name IN LISTS DAEMON_NACL_ARCH_NAME_LIST) add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${DEPS_DIR}/lib-armhf - ${FULL_OUTPUT_DIR}/lib-armhf + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${DEPS_DIR}/nacl_helper_bootstrap-${arch_name} + ${FULL_OUTPUT_DIR}/nacl_helper_bootstrap-${arch_name} ) - endif() + endforeach() - add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${DEPS_DIR}/nacl_helper_bootstrap - ${FULL_OUTPUT_DIR}/nacl_helper_bootstrap - ) - endif() + if (DAEMON_NACL_BOX64_EMULATION) + add_custom_command(TARGET runtime_deps PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${DEPS_DIR}/box64 + ${FULL_OUTPUT_DIR}/box64 + ) - # Win32 requires nacl_loader_amd64.exe in order to run on Win64 - if (YOKAI_TARGET_SYSTEM_WINDOWS AND YOKAI_TARGET_ARCH_I686) - add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${DEPS_DIR}/nacl_loader-amd64${CMAKE_EXECUTABLE_SUFFIX} - ${FULL_OUTPUT_DIR}/nacl_loader-amd64${CMAKE_EXECUTABLE_SUFFIX} - ) - add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${DEPS_DIR}/irt_core-amd64.nexe - ${FULL_OUTPUT_DIR}/irt_core-amd64.nexe - ) + add_custom_command(TARGET runtime_deps PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${DEPS_DIR}/libs-linux-amd64 + ${FULL_OUTPUT_DIR}/libs-linux-amd64 + ) + endif() endif() # Mac requires some libraries from external_deps diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4140a21f14..b447db1a27 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,9 +22,19 @@ pr: - .gitmodules jobs: - - job: Mac + - job: macOS pool: vmImage: 'macOS-15' + strategy: + matrix: + AppleClang amd64: + MACOS_ARCH: x86_64 + MACOS_VERSION: 10.14 + TEST: true + AppleClang arm64: + MACOS_ARCH: arm64 + MACOS_VERSION: 11.7 + TEST: false steps: - bash: | set -e @@ -56,12 +66,14 @@ jobs: cmake --version export CFLAGS='-Wno-c++14-extensions' export CXXFLAGS='-Wno-c++14-extensions' - cmake -Wdev -Wdeprecated -DUSE_PRECOMPILED_HEADER=0 -DUSE_WERROR=1 -DBE_VERBOSE=1 -DCMAKE_BUILD_TYPE=Release -DBUILD_DUMMY_APP=1 -DBUILD_DUMMY_GAMELOGIC=1 -DBUILD_TESTS=1 -H. -Bbuild + cmake -Wdev -Wdeprecated -DCMAKE_OSX_ARCHITECTURES=${MACOS_ARCH} -DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_VERSION} -DPREFER_EXTERNAL_LIBS=OFF -DUSE_PRECOMPILED_HEADER=0 -DUSE_WERROR=1 -DBE_VERBOSE=1 -DCMAKE_BUILD_TYPE=Release -DBUILD_DUMMY_APP=1 -DBUILD_DUMMY_GAMELOGIC=1 -DBUILD_TESTS=1 -H. -Bbuild cmake --build build -- -j`sysctl -n hw.logicalcpu` displayName: 'Build' - bash: | - set -e - build/test-ttyclient -pakpath pkg -set fs_basepak daemon -set vm.cgame.type 3 + if "${TEST}"; then + set -e + build/test-ttyclient -pakpath pkg -set fs_basepak daemon -set vm.cgame.type 3 + fi displayName: 'Test' - job: Linux diff --git a/cmake/DaemonGame.cmake b/cmake/DaemonGame.cmake index f6adde3c7c..b57dedeb94 100644 --- a/cmake/DaemonGame.cmake +++ b/cmake/DaemonGame.cmake @@ -68,10 +68,18 @@ set(SHAREDLIST_sgame # Function to setup all the Sgame/Cgame libraries include(CMakeParseArguments) -# The NaCl SDK only runs on amd64 or i686. +if (USE_NACL_SAIGO) + set(HAS_NACL_SDK ON) +elseif (CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME +AND (YOKAI_TARGET_ARCH_AMD64 OR YOKAI_TARGET_ARCH_I686)) + # The PNaCl SDK only runs on amd64 or i686. + set(HAS_NACL_SDK ON) +endif() + if (NOT FORK EQUAL 2) - if (CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME - AND (YOKAI_TARGET_ARCH_AMD64 OR YOKAI_TARGET_ARCH_I686)) + if (HAS_NACL_SDK) + include(DaemonNaclArchitecture) + # can be loaded by daemon with vm.[sc]game.type 0 or 1 option(BUILD_GAME_NACL "Build the NaCl \"pexe\" and \"nexe\" gamelogic modules for enabled architecture targets, required to host mods." OFF) @@ -89,10 +97,17 @@ if (NOT FORK EQUAL 2) set(NACL_TARGETS "${BUILD_GAME_NACL_TARGETS}") endif() - foreach(NACL_TARGET ${NACL_TARGETS}) + foreach(NACL_TARGET IN LISTS NACL_TARGETS) + daemon_detect_nacl_arch("${NACL_TARGET}") + + set(NACL_TARGETS "${DAEMON_NACL_ARCH_NAME_LIST}") + endforeach() + + foreach(NACL_TARGET IN LISTS NACL_TARGETS) set(IS_NACL_VALID_TARGET OFF) - foreach(NACL_VALID_TARGET ${NACL_ALL_TARGETS}) - if(NACL_TARGET STREQUAL NACL_VALID_TARGET) + + foreach(NACL_VALID_TARGET IN LISTS NACL_ALL_TARGETS) + if (NACL_TARGET STREQUAL NACL_VALID_TARGET) set(IS_NACL_VALID_TARGET ON) endif() endforeach() diff --git a/cmake/DaemonNacl.cmake b/cmake/DaemonNacl.cmake index e37bf06844..cc5c5aef54 100644 --- a/cmake/DaemonNacl.cmake +++ b/cmake/DaemonNacl.cmake @@ -26,7 +26,7 @@ # Native client -option(USE_NACL_SAIGO "Use Saigo toolchain to build NaCl executables" OFF) +option(USE_NACL_SAIGO "Use the Saigo toolchain to build NaCl executables" ON) if (YOKAI_TARGET_SYSTEM_NACL) # Build nexe binary. diff --git a/cmake/DaemonNaclHost.cmake b/cmake/DaemonNaclArchitecture.cmake similarity index 68% rename from cmake/DaemonNaclHost.cmake rename to cmake/DaemonNaclArchitecture.cmake index 7172e71d55..fe9a0b84a6 100644 --- a/cmake/DaemonNaclHost.cmake +++ b/cmake/DaemonNaclArchitecture.cmake @@ -24,41 +24,61 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -function(daemon_detect_nacl_arch) - set(target_arch "${YOKAI_TARGET_ARCH_NAME}") - set(nacl_arch "${target_arch}") +function(daemon_detect_nacl_arch target_arch) + macro(add_nacl_arch arch_name) + list(APPEND nacl_arch_list "${arch_name}") + message(STATUS "Available NaCl architecture: ${arch_name}") + endmacro() + + # NaCl runtime is only available on architectures that have a NaCl loader. + set(nacl_runtime_arch "amd64" "i686" "armhf") + + if (YOKAI_TARGET_SYSTEM_WINDOWS) + if("${target_arch}" STREQUAL "amd64") + add_nacl_arch("${target_arch}") + elseif("${target_arch}" STREQUAL "i686") + # Win32 requires nacl_loader-amd64.exe in order to run on Win64 + add_nacl_arch("${target_arch}") + add_nacl_arch("amd64") + endif() + elseif (YOKAI_TARGET_SYSTEM_LINUX_COMPATIBILITY OR YOKAI_TARGET_SYSTEM_XDG_COMPATIBILITY) + if ("${target_arch}" IN_LIST nacl_runtime_arch) + add_nacl_arch("${target_arch}") + endif() - if (YOKAI_TARGET_SYSTEM_LINUX_COMPATIBILITY OR YOKAI_TARGET_SYSTEM_XDG_COMPATIBILITY) set(armhf_usage "arm64" "armel") - set(box64_usage "ppc64el" "riscv64") + set(box64_usage "arm64" "ppc64el" "riscv64" "loong64") if ("${target_arch}" IN_LIST armhf_usage) # Load 32-bit armhf nexe on 64-bit arm64 engine on Linux with multiarch. # The nexe is system agnostic so there should be no difference with armel. - set(nacl_arch "armhf") - elseif ("${target_arch}" IN_LIST box64_usage) + add_nacl_arch("armhf") + endif() + + if ("${target_arch}" IN_LIST box64_usage) option(DAEMON_NACL_BOX64_EMULATION "Use Box64 to emulate x86_64 NaCl loader on unsupported platforms" ON) + if (DAEMON_NACL_BOX64_EMULATION) # Use Box64 to run x86_64 NaCl loader and amd64 nexe. # Box64 must be installed and available in PATH at runtime. - set(nacl_arch "amd64") + add_nacl_arch("amd64") add_definitions(-DDAEMON_NACL_BOX64_EMULATION) endif() endif() elseif (YOKAI_TARGET_SYSTEM_MACOS) - if ("${target_arch}" STREQUAL "arm64") + if ("${target_arch}" STREQUAL "amd64") + add_nacl_arch("${target_arch}") + elseif ("${target_arch}" STREQUAL "arm64") # You can get emulated NaCl going like this: # cp external_deps/macos-amd64-default_10/{nacl_loader,irt_core-amd64.nexe} build/ - set(nacl_arch "amd64") + add_nacl_arch("amd64") endif() endif() - string(TOUPPER "${nacl_arch}" nacl_arch_upper) + if (nacl_arch_list) + list(GET nacl_arch_list 0 nacl_arch) - # NaCl runtime is only available on architectures that have a NaCl loader. - set(nacl_runtime_arch "amd64" "i686" "armhf") - if ("${nacl_arch}" IN_LIST nacl_runtime_arch) - message(STATUS "Detected NaCl architecture: ${nacl_arch}") + message(STATUS "Primary NaCl architecture: ${nacl_arch}") add_definitions(-DDAEMON_NACL_RUNTIME_ENABLED) else() @@ -69,15 +89,6 @@ function(daemon_detect_nacl_arch) # The DAEMON_NACL_ARCH_NAME variable contributes to the nexe file name. set(DAEMON_NACL_ARCH_NAME "${nacl_arch}" PARENT_SCOPE) - - set(DAEMON_NACL_ARCH_NAME_UPPER "${nacl_arch_upper}" PARENT_SCOPE) + # Those names are used to copy the loader and the IRT binaries. + set(DAEMON_NACL_ARCH_NAME_LIST "${nacl_arch_list}" PARENT_SCOPE) endfunction() - -daemon_detect_nacl_arch() - -# Makes possible to do that in CMake code: -# > if (DAEMON_NACL_ARCH_ARMHF) -set("DAEMON_NACL_ARCH_${DAEMON_NACL_ARCH_NAME_UPPER}" ON) - -# Add printable strings to the executable. -yokai_add_buildinfo("char*" "DAEMON_NACL_ARCH_STRING" "\"${DAEMON_NACL_ARCH_NAME}\"") diff --git a/cmake/Yokai/Architecture.cmake b/cmake/Yokai/Architecture.cmake index 7a62bcfce0..ad2970ac00 100644 --- a/cmake/Yokai/Architecture.cmake +++ b/cmake/Yokai/Architecture.cmake @@ -28,20 +28,104 @@ # Architecture detection. ################################################################################ -# When adding a new architecture, look at all the places YOKAI_TARGET_ARCH is used. +# When adding a new architecture, look at all the places YOKAI_HOST_ARCH +# and YOKAI_TARGET_ARCH are used. option(USE_ARCH_INTRINSICS "Enable custom code using intrinsics functions or asm declarations" ON) mark_as_advanced(USE_ARCH_INTRINSICS) -function(yokai_detect_arch) +function(yokai_detect_host_arch) + set(arch_name "unknown") + + string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" processor_lower) + + foreach(name + "arm" + "arm64" + "i686" + "mipsel" + "ppc64" + "riscv64" + ) + if ("${processor_lower}" STREQUAL "${name}") + set(arch_name "${processor_lower}") + endif() + endforeach() + + if ("${arch_name}" STREQUAL "unknown") + set(ARCH_em64t "amd64") + set(ARCH_x86_64 "amd64") + set(ARCH_armv7l, "arm") + set(ARCH_armv6l, "arm") + set(ARCH_aarch64 "arm64") + set(ARCH_loongarch64, "loong64") + set(ARCH_ppc64le, "ppc64el") + + foreach(name + "amd64" + "arm" + ) + if ("${ARCH_${processor_lower}}" STREQUAL "${name}") + set(arch_name "${ARCH_${processor_lower}}") + endif() + endforeach() + endif() + + if ("${arch_name}" STREQUAL "unknown") + if ("${processor_lower}") + message(WARNING "Undocumented host architecture: ${processor_lower}") + else() + message(WARNING "Undocumented host architecture") + endif() + + set(arch_name "${processor_lower}") + endif() + + string(TOUPPER "${arch_name}" arch_name_upper) + + set(YOKAI_HOST_ARCH_NAME "${arch_name}" PARENT_SCOPE) + set(YOKAI_HOST_ARCH_NAME_UPPER "${arch_name_upper}" PARENT_SCOPE) + + # Makes possible to do that in CMake code: + # > if (YOKAI_HOST_ARCH_AMD64) + set("YOKAI_HOST_ARCH_${arch_name_upper}" ON PARENT_SCOPE) + + if ("${arch_name}" STREQUAL "unknown") + message(WARNING "Unknown host architecture: ${processor_lower}") + + set(arch_name "${processor_lower}") + endif() + + set(arm_CHILD + "armel" + "armhf" + ) + + foreach(name + "arm" + ) + if ("${arch_name}" STREQUAL "${name}") + message(STATUS "Parent architecture: ${name}, can be ${AMBIGUOUS_${name}}") + + foreach(child_name ${${name}_CHILD}) + string(TOUPPER "${child_name}" child_name_upper) + set(YOKAI_HOST_ARCH_${child_name_upper}_PARENT ON PARENT_SCOPE) + endforeach() + endif() + endforeach() +endfunction() + +function(yokai_detect_target_arch) yokai_run_detection("TARGET" "ARCH" "Architecture.c" "") set(YOKAI_TARGET_ARCH_NAME "${arch_name}" PARENT_SCOPE) set(YOKAI_TARGET_ARCH_NAME_UPPER "${arch_name_upper}" PARENT_SCOPE) - message(STATUS "Detected target architecture: ${arch_name}") - add_definitions(-DYOKAI_ARCH_${arch_name_upper}) + + # Makes possible to do that in CMake code: + # > if (YOKAI_TARGET_ARCH_AMD64) + set("YOKAI_TARGET_ARCH_${arch_name_upper}" ON PARENT_SCOPE) endfunction() function(yokai_set_arch_intrinsics name) @@ -50,9 +134,6 @@ function(yokai_set_arch_intrinsics name) add_definitions(-DYOKAI_USE_ARCH_INTRINSICS_${name_upper}) endfunction() -option(USE_ARCH_INTRINSICS "Enable custom code using intrinsics functions or asm declarations" ON) -mark_as_advanced(USE_ARCH_INTRINSICS) - function(yokai_set_intrinsics) if (USE_ARCH_INTRINSICS) # Makes possible to do that in C++ code: @@ -61,7 +142,6 @@ function(yokai_set_intrinsics) # Makes possible to do that in C++ code: # > if defined(YOKAI_USE_ARCH_INTRINSICS_AMD64) - # > if defined(YOKAI_USE_ARCH_INTRINSICS_I686) yokai_set_arch_intrinsics("${YOKAI_TARGET_ARCH_NAME}") set(amd64_PARENT "i686") @@ -76,14 +156,49 @@ function(yokai_set_intrinsics) endif() endfunction() -yokai_detect_arch() -yokai_set_intrinsics() +yokai_detect_host_arch() +yokai_detect_target_arch() -# Makes possible to do that in CMake code: -# > if (YOKAI_TARGET_ARCH_ARM64) -set("YOKAI_TARGET_ARCH_${YOKAI_TARGET_ARCH_NAME_UPPER}" ON) +if (YOKAI_HOST_ARCH_UNKNOWN AND NOT YOKAI_TARGET_ARCH_UNKNOWN) + message(WARNING "Assuming the host architecture is the same as the target: ${YOKAI_TARGET_ARCH_NAME}") + set(YOKAI_HOST_ARCH_NAME "${YOKAI_TARGET_ARCH_NAME}") + set(YOKAI_HOST_ARCH_NAME_UPPER "${YOKAI_TARGET_ARCH_NAME_UPPER}") + set(YOKAI_HOST_ARCH_${YOKAI_HOST_ARCH_NAME_UPPER} ON) + unset(YOKAI_HOST_ARCH_UNKNOWN) +endif() + +if (YOKAI_TARGET_ARCH_UNKNOWN AND NOT YOKAI_HOST_ARCH_UNKNOWN) + message(WARNING "Assuming the target architecture is the same as the host: ${YOKAI_TARGET_ARCH_NAME}") + set(YOKAI_TARGET_ARCH_NAME "${YOKAI_HOST_ARCH_NAME}") + set(YOKAI_TARGET_ARCH_NAME_UPPER "${YOKAI_HOST_ARCH_NAME_UPPER}") + set(YOKAI_TARGET_ARCH_${YOKAI_TARGET_ARCH_NAME_UPPER} ON) + unset(YOKAI_TARGET_ARCH_UNKNOWN) +endif() + +if (YOKAI_HOST_ARCH_UNKNOWN) + message(WARNING "Unknown host architecture") +else() + message(STATUS "Detected host architecture: ${YOKAI_HOST_ARCH_NAME}") +endif() + +if (YOKAI_TARGET_ARCH_UNKNOWN) + message(WARNING "Unknown target architecture") +else() + message(STATUS "Detected target architecture: ${YOKAI_TARGET_ARCH_NAME}") +endif() + +if (NOT "${YOKAI_HOST_ARCH_NAME}" STREQUAL "${YOKAI_TARGET_ARCH_NAME}") + if ("${YOKAI_HOST_ARCH_${YOKAI_TARGET_ARCH_NAME}_PARENT}") + message(STATUS "Assuming no architecture cross-compilation") + else() + message(STATUS "Detected architecture cross-compilation") + set(YOKAI_TARGET_CROSS ON) + endif() +endif() if (YOKAI_SOURCE_GENERATOR) # Add printable strings to the executable. yokai_add_buildinfo("char*" "YOKAI_ARCH_STRING" "\"${YOKAI_TARGET_ARCH_NAME}\"") endif() + +yokai_set_intrinsics() diff --git a/cmake/Yokai/Detection/Architecture.c b/cmake/Yokai/Detection/Architecture.c index ae973a210a..9d54dae40c 100644 --- a/cmake/Yokai/Detection/Architecture.c +++ b/cmake/Yokai/Detection/Architecture.c @@ -107,6 +107,11 @@ platform variants we cannot support anyway. */ #elif defined(Q_PROCESSOR_RISCV_64) #pragma message(REPORT_NAME("riscv64")) +/* Devices like: + - Loongson 3A6000, 3A5000… */ +#elif defined(Q_PROCESSOR_LOONGARCH_64) + #pragma message(REPORT_NAME("loong64")) + /* Remaining native NaCl architecture. */ #elif defined(Q_PROCESSOR_MIPS_32) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN diff --git a/cmake/Yokai/Detection/qprocessordetection.h b/cmake/Yokai/Detection/qprocessordetection.h index 1b6139152e..7dbd38d316 100644 --- a/cmake/Yokai/Detection/qprocessordetection.h +++ b/cmake/Yokai/Detection/qprocessordetection.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #if 0 @@ -51,8 +52,8 @@ Alpha is bi-endian, use endianness auto-detection implemented below. */ -// #elif defined(__alpha__) || defined(_M_ALPHA) -// # define Q_PROCESSOR_ALPHA +#if defined(__alpha__) || defined(_M_ALPHA) +# define Q_PROCESSOR_ALPHA // Q_BYTE_ORDER not defined, use endianness auto-detection /* @@ -61,8 +62,8 @@ ARM is bi-endian, detect using __ARMEL__ or __ARMEB__, falling back to auto-detection implemented below. */ -#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__) -# if defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64) +#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__) || defined(_ARM64EC_) +# if defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64) || defined(_ARM64EC_) # define Q_PROCESSOR_ARM_64 # define Q_PROCESSOR_WORDSIZE 8 # else @@ -78,7 +79,8 @@ || defined(__aarch64__) \ || defined(__ARMv8__) \ || defined(__ARMv8_A__) \ - || defined(_M_ARM64) + || defined(_M_ARM64) \ + || defined (_ARM64EC_) # define Q_PROCESSOR_ARM 8 # elif defined(__ARM_ARCH_7__) \ || defined(__ARM_ARCH_7A__) \ @@ -116,7 +118,10 @@ # else # error "ARM architecture too old" # endif -# if defined(__ARMEL__) || defined(_M_ARM64) +# if defined(_ARM64EC_) +# define Q_PROCESSOR_ARM_64_EC +# endif +# if defined(__ARMEL__) || defined(_M_ARM64) || defined(_ARM64EC_) # define Q_BYTE_ORDER Q_LITTLE_ENDIAN # elif defined(__ARMEB__) # define Q_BYTE_ORDER Q_BIG_ENDIAN @@ -199,6 +204,20 @@ # define Q_PROCESSOR_WORDSIZE 8 // Q_BYTE_ORDER not defined, use endianness auto-detection +/* + LoongArch family, known variants: 32- and 64-bit + + LoongArch is little-endian. +*/ +#elif defined(__loongarch__) +# define Q_PROCESSOR_LOONGARCH +# if __loongarch_grlen == 64 +# define Q_PROCESSOR_LOONGARCH_64 +# else +# define Q_PROCESSOR_LOONGARCH_32 +# endif +# define Q_BYTE_ORDER Q_LITTLE_ENDIAN + /* Motorola 68000 family, no revisions or variants @@ -327,6 +346,8 @@ # define Q_PROCESSOR_WORDSIZE 8 #ifdef QT_COMPILER_SUPPORTS_SSE2 # define Q_PROCESSOR_X86 6 // enables SIMD support +# define Q_PROCESSOR_X86_64 // wasm64 +# define Q_PROCESSOR_WASM_64 #endif #endif diff --git a/cmake/Yokai/System.cmake b/cmake/Yokai/System.cmake index a8e9f329d1..e8de0d447c 100644 --- a/cmake/Yokai/System.cmake +++ b/cmake/Yokai/System.cmake @@ -34,89 +34,101 @@ function(yokai_detect_host_system) set(system_name "Unknown") - foreach(name Linux;FreeBSD;Android;Windows) + foreach(name + "Linux" + "FreeBSD" + "Android" + "Windows" + ) if (CMAKE_HOST_SYSTEM_NAME MATCHES "${name}") - set(system_name "${CMAKE_SYSTEM_NAME}") + set(system_name "${CMAKE_HOST_SYSTEM_NAME}") endif() endforeach() - if (system_name STREQUAL "Unknown") + if ("${system_name}" STREQUAL "Unknown") set(SYSTEM_Darwin "macOS") set(SYSTEM_MSYS "Windows") - foreach(name Darwin;MSYS) + foreach(name + "Darwin" + "MSYS" + ) if ("${CMAKE_HOST_SYSTEM_NAME}" MATCHES "${name}") set(system_name "${SYSTEM_${name}}") endif() endforeach() endif() - if (system_name STREQUAL "Unknown") - message(WARNING "Host system detection failed, may misdetect the target as the host.") - - if (WIN32) - set(system_name "Windows") - elseif (APPLE) - set(system_name "macOS") - endif() - endif() + string(TOUPPER "${system_name}" system_name_upper) set(YOKAI_HOST_SYSTEM_NAME "${system_name}" PARENT_SCOPE) set(YOKAI_HOST_SYSTEM_NAME_UPPER "${system_name_upper}" PARENT_SCOPE) + + # Makes possible to do that in CMake code: + # > if (YOKAI_HOST_SYSTEM_LINUX) + set(YOKAI_HOST_SYSTEM_${system_name_upper} ON PARENT_SCOPE) endfunction() -function(yokai_detect_system) +function(yokai_detect_target_system) yokai_run_detection("TARGET" "SYSTEM" "System.c" "Linux") - if (system_name STREQUAL "Unknown") - detect_cmake_host_system("system_name") - endif() - set(YOKAI_TARGET_SYSTEM_NAME "${system_name}" PARENT_SCOPE) set(YOKAI_TARGET_SYSTEM_NAME_UPPER "${system_name_upper}" PARENT_SCOPE) + + # Makes possible to do that in CMake code: + # > if (YOKAI_TARGET_SYSTEM_LINUX) + set(YOKAI_TARGET_SYSTEM_${system_name_upper} ON PARENT_SCOPE) endfunction() yokai_detect_host_system() -yokai_detect_system() - -if ("${YOKAI_HOST_SYSTEM_NAME}" STREQUAL "Unknown") - message(WARNING "Unknown host system") -endif() +yokai_detect_target_system() -if ("${YOKAI_TARGET_SYSTEM_NAME}" STREQUAL "Unknown") - message(WARNING "Unknown target system") -endif() - -if ("${YOKAI_HOST_SYSTEM_NAME}" STREQUAL "Unknown" AND NOT "${YOKAI_TARGET_SYSTEM_NAME}" STREQUAL "Unknown") +if (YOKAI_HOST_SYSTEM_UNKNOWN AND NOT YOKAI_TARGET_SYSTEM_UNKNOWN) message(WARNING "Assuming the host system is the same as the target: ${YOKAI_TARGET_SYSTEM_NAME}") set(YOKAI_HOST_SYSTEM_NAME "${YOKAI_TARGET_SYSTEM_NAME}") + set(YOKAI_HOST_SYSTEM_NAME_UPPER "${YOKAI_TARGET_SYSTEM_NAME_UPPER}") + set(YOKAI_HOST_SYSTEM_${YOKAI_HOST_SYSTEM_NAME_UPPER} ON) + unset(YOKAI_HOST_SYSTEM_UNKNOWN) endif() -if ("${YOKAI_TARGET_SYSTEM_NAME}" STREQUAL "Unknown" AND NOT "${YOKAI_HOST_SYSTEM_NAME}" STREQUAL "Unknown") +if (YOKAI_TARGET_SYSTEM_UNKNOWN AND NOT YOKAI_HOST_SYSTEM_UNKNOWN) message(WARNING "Assuming the target system is the same as the host: ${YOKAI_TARGET_SYSTEM_NAME}") set(YOKAI_TARGET_SYSTEM_NAME "${YOKAI_HOST_SYSTEM_NAME}") + set(YOKAI_TARGET_SYSTEM_NAME_UPPER "${YOKAI_HOST_SYSTEM_NAME_UPPER}") + set(YOKAI_TARGET_SYSTEM_${YOKAI_TARGET_SYSTEM_NAME_UPPER} ON) + unset(YOKAI_TARGET_SYSTEM_UNKNOWN) +endif() + +if (YOKAI_HOST_SYSTEM_UNKNOWN) + message(WARNING "Unknown host system") +else() + message(STATUS "Detected host system: ${YOKAI_HOST_SYSTEM_NAME}") endif() -message(STATUS "Detected host system: ${YOKAI_HOST_SYSTEM_NAME}") -message(STATUS "Detected target system: ${YOKAI_TARGET_SYSTEM_NAME}") +if (YOKAI_TARGET_SYSTEM_UNKNOWN) + message(WARNING "Unknown target system") +else() + message(STATUS "Detected target system: ${YOKAI_TARGET_SYSTEM_NAME}") +endif() if (NOT "${YOKAI_HOST_SYSTEM_NAME}" STREQUAL "${YOKAI_TARGET_SYSTEM_NAME}") - message(STATUS "Detected cross-compilation") + message(STATUS "Detected system cross-compilation") + set(YOKAI_SYSTEM_CROSS ON) endif() -# Makes possible to do that in CMake code: -# > if (YOKAI_HOST_SYSTEM_LINUX) -# > if (YOKAI_TARGET_SYSTEM_WINDOWS) -set("YOKAI_HOST_SYSTEM_${YOKAI_HOST_SYSTEM_NAME_UPPER}" ON) -set("YOKAI_TARGET_SYSTEM_${YOKAI_TARGET_SYSTEM_NAME_UPPER}" ON) - # This is for systems behaving similarly to a Linux Desktop, # implementing standards like FHS, XDG, GLVND… # Makes possible to do that in CMake code: # > if (YOKAI_HOST_SYSTEM_XDG_COMPATIBILITY) # > if (YOKAI_TARGET_SYSTEM_XDG_COMPATIBILITY) -foreach(name LINUX;FREEBSD) - foreach(slug HOST_SYSTEM;TARGET_SYSTEM) +foreach(name + "LINUX" + "FREEBSD" +) + foreach(slug + "HOST_SYSTEM" + "TARGET_SYSTEM" + ) if (YOKAI_${slug}_${name}) set(YOKAI_${slug}_XDG_COMPATIBILITY ON) endif() diff --git a/external_deps/build.sh b/external_deps/build.sh index e5e77cf91a..b73764b28f 100755 --- a/external_deps/build.sh +++ b/external_deps/build.sh @@ -9,11 +9,12 @@ WORK_DIR="${PWD}" # This should match the DEPS_VERSION in CMakeLists.txt. # This is mostly to ensure the path the files end up at if you build deps yourself # are the same as the ones when extracting from the downloaded packages. -DEPS_VERSION=11 +DEPS_VERSION=12 # Package download pages PKGCONFIG_BASEURL='https://pkg-config.freedesktop.org/releases' NASM_BASEURL='https://www.nasm.us/pub/nasm/releasebuilds' +JWASM_BASEURL='https://api.github.com/repos/JWasm/JWasm/zipball' ZLIB_BASEURL='https://zlib.net/fossils' GMP_BASEURL='https://gmplib.org/download/gmp' NETTLE_BASEURL='https://mirror.cyberbits.eu/gnu/nettle' @@ -31,6 +32,8 @@ OGG_BASEURL='https://downloads.xiph.org/releases/ogg' VORBIS_BASEURL='https://downloads.xiph.org/releases/vorbis' OPUS_BASEURL='https://downloads.xiph.org/releases/opus' OPUSFILE_BASEURL='https://downloads.xiph.org/releases/opus' +BOX64_BASEURL='https://api.github.com/repos/ptitSeb/box64/zipball' +SAIGOSDK_BASEURL='https://github.com/DaemonEngine/saigo-release-scripts/releases' # No index. NACLSDK_BASEURL='https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk' # No index. @@ -42,54 +45,61 @@ WASMTIME_BASEURL='https://github.com/bytecodealliance/wasmtime/releases' # Package versions PKGCONFIG_VERSION=0.29.2 NASM_VERSION=2.16.03 -ZLIB_VERSION=1.3.1 +JWASM_REVISION='a5c4ea03cc0545a15d81a354251b5f534bef7a1b' +ZLIB_VERSION=1.3.2 GMP_VERSION=6.3.0 -NETTLE_VERSION=3.10.2 -CURL_VERSION=8.15.0 -SDL3_VERSION=3.2.22 -GLEW_VERSION=2.2.0 -PNG_VERSION=1.6.50 -JPEG_VERSION=3.1.1 +NETTLE_VERSION=4.0 +CURL_VERSION=8.21.0 +SDL3_VERSION=3.4.10 +GLEW_VERSION=2.3.1 +PNG_VERSION=1.6.58 +JPEG_VERSION=3.1.4.1 # WebP 1.6.0 introduced AVX2 intrinsics that are not available on # the GCC 10 compiler provided by Debian Bullseye. WEBP_VERSION=1.5.0 +# OpenAL 0.25.0 requires C++20 that is not availabnle on +# the GCC 10 compiler provided by Debian Bullseye. OPENAL_VERSION=1.24.3 OGG_VERSION=1.3.6 VORBIS_VERSION=1.3.7 -OPUS_VERSION=1.5.2 +OPUS_VERSION=1.6.1 OPUSFILE_VERSION=0.12 +BOX64_REVISION='b1d094f9bd37cd69865c56d72a94747b22c16dd6' +SAIGOSDK_VERSION='21.0-20260625' NACLSDK_VERSION=44.0.2403.155 -NACLRUNTIME_REVISION=2aea5fcfce504862a825920fcaea1a8426afbd6f +NACLRUNTIME_REVISION='13a7fdd548d2d3c7c6480580cffacaa6b6a90e79' NCURSES_VERSION=6.5 WASISDK_VERSION=16.0 WASMTIME_VERSION=2.0.2 -# Require the compiler names to be explicitly hardcoded, we should not inherit them -# from environment as we heavily cross-compile. -CC='false' -CXX='false' -# Set defaults. -LD='ld' -AR='ar' -RANLIB='ranlib' -PKG_CONFIG='pkg-config' -CROSS_PKG_CONFIG_PATH='' -LIBS_SHARED='OFF' -LIBS_STATIC='ON' -CMAKE_TOOLCHAIN='' -# Always reset flags, we heavily cross-compile and must not inherit any stray flag -# from environment. -CPPFLAGS='' -CFLAGS='-O3 -fPIC' -CXXFLAGS='-O3 -fPIC' -LDFLAGS='-O3 -fPIC' - log() { level="${1}"; shift printf '%s: %s\n' "${level}" "${@}" >&2 [ "${level}" != 'ERROR' ] } +smart_copy() { + if ! cp --reflink=auto -P "${@}" 2>/dev/null + then + cp -P "${@}" + fi +} + +dedupe_dir () +{ + if command -v jdupes >/dev/null 2>&1 + then + log STATUS 'Using jdupes for deduplication' + jdupes -r -L "${@}" + elif command -v rdfind >/dev/null 2>&1 + then + log STATUS 'Using rdfind for deduplication' + rdfind -makeresultsfile false -makehardlinks true "${@}" + else + log WARNING 'WARN: missing jdupes or rdfind, will not deduplicate' + fi +} + # Extract an archive into the given subdirectory of the build dir and cd to it # Usage: extract extract() { @@ -122,7 +132,7 @@ extract() { *.dmg) local dmg_temp_dir="$(mktemp -d)" hdiutil attach -mountpoint "${dmg_temp_dir}" "${archive_file}" - cp -R "${dmg_temp_dir}/"* "${extract_dir}/" + smart_copy -R "${dmg_temp_dir}/." "${extract_dir}/" hdiutil detach "${dmg_temp_dir}" rmdir "${dmg_temp_dir}" ;; @@ -176,6 +186,18 @@ download_extract() { configure_build() { local configure_args=() + case "${HOST}" in + native) + configure_args+=(--prefix="${NATIVE_PREFIX}") + configure_args+=(--libdir="${NATIVE_PREFIX}/lib") + ;; + *) + configure_args+=(--host="${HOST}") + configure_args+=(--prefix="${PREFIX}") + configure_args+=(--libdir="${PREFIX}/lib") + ;; + esac + if [ "${LIBS_SHARED}" = 'ON' ] then configure_args+=(--enable-shared) @@ -197,9 +219,6 @@ configure_build() { fi ./configure \ - --host="${HOST}" \ - --prefix="${PREFIX}" \ - --libdir="${PREFIX}/lib" \ "${configure_args[@]}" make @@ -223,6 +242,24 @@ get_compiler_arg1() { cmake_build() { local cmake_args=() + case "${HOST}" in + native) + cmake_args+=(-DCMAKE_PREFIX_PATH="${NATIVE_PREFIX}") + cmake_args+=(-DCMAKE_INSTALL_PREFIX="${NATIVE_PREFIX}") + ;; + *) + cmake_args+=(-DCMAKE_PREFIX_PATH="${PREFIX}") + cmake_args+=(-DCMAKE_INSTALL_PREFIX="${PREFIX}") + ;; + esac + + case "${HOST}" in + macos-*) + cmake_args+=(-DCMAKE_OSX_ARCHITECTURES="${MACOS_ARCH}") + cmake_args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET="${MACOS_VERSION}") + ;; + esac + cmake_args+=(-DCMAKE_C_COMPILER="$(get_compiler_name ${CC})") cmake_args+=(-DCMAKE_CXX_COMPILER="$(get_compiler_name ${CXX})") cmake_args+=(-DCMAKE_C_COMPILER_ARG1="$(get_compiler_arg1 ${CC})") @@ -231,17 +268,21 @@ cmake_build() { cmake_args+=(-DCMAKE_CXX_FLAGS="${CXXFLAGS}") cmake_args+=(-DCMAKE_EXE_LINKER_FLAGS="${LDFLAGS}") + if [ -n "${CMAKE_TOOLCHAIN:-}" ] + then + cmake_args+=(-DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN}") + fi + # Check for ${@} not being empty to workaround a macOS bash limitation. if [ -n "${1:-}" ] then cmake_args+=("${@}") fi + rm -rf build + cmake -S . -B build \ - -DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN}" \ -DCMAKE_BUILD_TYPE='Release' \ - -DCMAKE_PREFIX_PATH="${PREFIX}" \ - -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ -DBUILD_SHARED_LIBS="${LIBS_SHARED}" \ "${cmake_args[@]}" @@ -249,42 +290,43 @@ cmake_build() { cmake --install build --strip } -# Build pkg-config, needed for opusfile. -# As a host-mode dependency it must be provided by the system when cross-compiling. -build_pkgconfig() { +# Build pkg-config, needed for opusfile on macos. +# It is part of the cross-compilation toolchain. +# As a host-mode native dependency it must be provided by the system when cross-compiling. +build_native-pkgconfig() { local dir_name="pkg-config-${PKGCONFIG_VERSION}" local archive_name="${dir_name}.tar.gz" - download_extract pkgconfig "${archive_name}" \ + download_extract native-pkgconfig "${archive_name}" \ "${PKGCONFIG_BASEURL}/${archive_name}" "${download_only}" && return cd "${dir_name}" - # Reset the environment variables, we don't cross-compile this, - # it is part of the cross-compilation toolchain. - # CXXFLAGS is unused. - CFLAGS='-Wno-error=int-conversion' \ - LDFLAGS='' \ - HOST='' \ - configure_build \ + ( + setup_platform 'native' + CFLAGS='-Wno-error=int-conversion' \ + configure_build \ --with-internal-glib + ) } -# Build NASM -build_nasm() { +# Build NASM, needed for jpeg on macos-amd64. +# It is part of the compilation toolchain. +# As a host-mode native dependency it must be provided by the system when compiling. +build_native-nasm() { case "${PLATFORM}" in - macos-*-*) + macos-amd64-*) local dir_name="nasm-${NASM_VERSION}" local archive_name="${dir_name}-macosx.zip" - download_extract nasm "${archive_name}" \ + download_extract native-nasm "${archive_name}" \ "${NASM_BASEURL}/${NASM_VERSION}/macosx/${archive_name}" "${download_only}" && return - cp "${dir_name}/nasm" "${PREFIX}/bin" + smart_copy "${dir_name}/nasm" "${NATIVE_PREFIX}/bin" ;; *) log ERROR 'Unsupported platform for NASM' @@ -292,6 +334,35 @@ build_nasm() { esac } +# Build JWasm, needed for naclruntime for windows. +# It is part of the compilation toolchain. +# As a host-mode native dependency it must be provided by the system when compiling. +build_native-jwasm() { + case "${PLATFORM}" in + windows-*-*) + local dir_name="JWasm-JWasm-${JWASM_REVISION:0:7}" + local archive_name="jwasm-${JWASM_REVISION}.zip" + + download_extract native-jwasm "${archive_name}" \ + "${JWASM_BASEURL}/${JWASM_REVISION}" + + "${download_only}" && return + + cd "${dir_name}" + + ( + setup_platform 'native' + cmake_build + smart_copy "build/jwasm${EXE_EXT}" "${NATIVE_PREFIX}/bin/jwasm${EXE_EXT}" + ) + ;; + *) + log ERROR 'Unsupported platform for JWasm' + ;; + esac + +} + # Build zlib build_zlib() { # Only the latest zlib version is provided as tar.xz, the @@ -455,16 +526,18 @@ build_sdl3() { case "${PLATFORM}" in windows-*-mingw) cd "${dir_name}" - cp -rv "${HOST}"/* "${PREFIX}/" + smart_copy -R "${HOST}/." "${PREFIX}/" rm "${PREFIX}/lib/libSDL3_test.a" rm "${PREFIX}/lib/cmake/SDL3/SDL3testTargets"*.cmake ;; windows-*-msvc) cd "${dir_name}" - mkdir -p "${PREFIX}/SDL3/cmake" - cp "cmake/"* "${PREFIX}/SDL3/cmake" - mkdir -p "${PREFIX}/SDL3/include/SDL3" - cp "include/SDL3/"* "${PREFIX}/SDL3/include/SDL3" + mkdir -p "${PREFIX}/SDL3" + rm -rf "${PREFIX}/SDL3/cmake" + smart_copy -R "cmake/." "${PREFIX}/SDL3/cmake/" + mkdir -p "${PREFIX}/SDL3/include" + rm -rf "${PREFIX}/SDL3/include/SDL3" + smart_copy -R "include/SDL3/." "${PREFIX}/SDL3/include/SDL3/" case "${PLATFORM}" in *-i686-*) @@ -479,18 +552,20 @@ build_sdl3() { esac mkdir -p "${PREFIX}/SDL3/${sdl3_lib_dir}" - cp "${sdl3_lib_dir}/SDL3.lib" "${PREFIX}/SDL3/${sdl3_lib_dir}" - cp "${sdl3_lib_dir}/"*.dll "${PREFIX}/SDL3/${sdl3_lib_dir}" + smart_copy "${sdl3_lib_dir}/SDL3.lib" "${PREFIX}/SDL3/${sdl3_lib_dir}/" + smart_copy "${sdl3_lib_dir}/"*.dll "${PREFIX}/SDL3/${sdl3_lib_dir}/" ;; macos-*-*) - cp -R "SDL3.xcframework/macos-arm64_x86_64/SDL3.framework" "${PREFIX}/lib" + rm -rf "${PREFIX}/lib/SDL3.framework" + smart_copy -R "SDL3.xcframework/macos-arm64_x86_64/SDL3.framework/." "${PREFIX}/lib/SDL3.framework/" ;; *) cd "${dir_name}" cmake_build \ -DSDL_TEST_LIBRARY=OFF \ - -DSDL_AUDIO=OFF + -DSDL_AUDIO=OFF \ + -DSDL_GPU=OFF ;; esac } @@ -550,7 +625,7 @@ build_glew() { windows-*-*) mv "${PREFIX}/lib/glew32.dll" "${PREFIX}/bin/" rm "${PREFIX}/lib/libglew32.a" - cp lib/libglew32.dll.a "${PREFIX}/lib/" + smart_copy lib/libglew32.dll.a "${PREFIX}/lib/" ;; macos-*-*) install_name_tool -id "@rpath/libGLEW.${GLEW_VERSION}.dylib" "${PREFIX}/lib/libGLEW.${GLEW_VERSION}.dylib" @@ -762,9 +837,9 @@ build_openal() { case "${PLATFORM}" in windows-*-*) cd "${dir_name}" - cp -r "include/AL" "${PREFIX}/include" - cp "libs/${openal_win_dir}/libOpenAL32.dll.a" "${PREFIX}/lib" - cp "bin/${openal_win_dir}/soft_oal.dll" "${PREFIX}/bin/OpenAL32.dll" + smart_copy -R "include/AL" "${PREFIX}/include" + smart_copy "libs/${openal_win_dir}/libOpenAL32.dll.a" "${PREFIX}/lib" + smart_copy "bin/${openal_win_dir}/soft_oal.dll" "${PREFIX}/bin/OpenAL32.dll" ;; *) cd "${dir_name}" @@ -879,6 +954,8 @@ build_opusfile() { cd "${dir_name}" + # The old configure script doesn't recognize the arm64 prefix. + HOST="${HOST/arm64-apple/aarch64-apple}" \ configure_build \ --disable-http } @@ -897,7 +974,7 @@ build_ncurses() { cd "${dir_name}" # Brutally disable writing to database - cp /dev/null misc/run_tic.in + smart_copy /dev/null misc/run_tic.in # Configure terminfo search dirs based on the ones used in Debian. By default it will only look in (only) the install directory. configure_build \ --with-strip-program="${STRIP}" \ @@ -907,6 +984,42 @@ build_ncurses() { --with-default-terminfo-dir=/usr/share/terminfo } +# Build box64 +build_box64() { + local dir_name="ptitSeb-box64-${BOX64_REVISION:0:7}" + local archive_name="box64-${BOX64_REVISION}.zip" + + download_extract box64 "${archive_name}" \ + "${BOX64_BASEURL}/${BOX64_REVISION}" + + "${download_only}" && return + + cd "${dir_name}" + + cmake_build + + smart_copy 'build/box64' "${PREFIX}/box64" + + mkdir -p "${PREFIX}/libs-linux-amd64" + smart_copy -L \ + '/usr/lib/x86_64-linux-gnu/libgcc_s.so.1' \ + "${PREFIX}/libs-linux-amd64/" +} + +# "Builds" (downloads) Saigo +build_saigosdk() { + local dir_name="saigocc-${PLATFORM_TARGET}_${SAIGOSDK_VERSION}" + local archive_name="${dir_name}.tar.xz" + + download_extract saigosdk "${archive_name}" \ + "${SAIGOSDK_BASEURL}/download/v${SAIGOSDK_VERSION}/${archive_name}" + + "${download_only}" && return + + rm -rf "${PREFIX}/saigo_newlib" + smart_copy -R "${dir_name}" "${PREFIX}/saigo_newlib" +} + # "Builds" (downloads) the WASI SDK build_wasisdk() { case "${PLATFORM}" in @@ -937,7 +1050,8 @@ build_wasisdk() { "${download_only}" && return - cp -r "${dir_name}" "${PREFIX}/wasi-sdk" + rm -rf "${PREFIX}/wasi-sdk" + smart_copy -R "${dir_name}" "${PREFIX}/wasi-sdk" } # "Builds" (downloads) wasmtime @@ -977,8 +1091,8 @@ build_wasmtime() { "${download_only}" && return cd "${dir_name}" - cp -r include/* "${PREFIX}/include" - cp -r lib/* "${PREFIX}/lib" + smart_copy -R 'include/.' "${PREFIX}/include/" + smart_copy -R 'lib/.' "${PREFIX}/lib/" } # Build the NaCl SDK @@ -986,17 +1100,14 @@ build_naclsdk() { case "${PLATFORM}" in windows-*-*) local NACLSDK_PLATFORM=win - local EXE=.exe local TAR_EXT=cygtar ;; macos-*-*) local NACLSDK_PLATFORM=mac - local EXE= local TAR_EXT=tar ;; linux-*-*) local NACLSDK_PLATFORM=linux - local EXE= local TAR_EXT=tar ;; esac @@ -1005,7 +1116,7 @@ build_naclsdk() { local NACLSDK_ARCH=x86_32 local DAEMON_ARCH=i686 ;; - *-amd64-*) + *-amd64-*|macos-arm64-*) local NACLSDK_ARCH=x86_64 local DAEMON_ARCH=amd64 ;; @@ -1022,24 +1133,18 @@ build_naclsdk() { "${download_only}" && return - cp pepper_*"/tools/irt_core_${NACLSDK_ARCH}.nexe" "${PREFIX}/irt_core-${DAEMON_ARCH}.nexe" - case "${PLATFORM}" in - linux-amd64-*) - ;; # Get sel_ldr from naclruntime package - *) - cp pepper_*"/tools/sel_ldr_${NACLSDK_ARCH}${EXE}" "${PREFIX}/nacl_loader${EXE}" - ;; - esac + smart_copy pepper_*"/tools/irt_core_${NACLSDK_ARCH}.nexe" "${PREFIX}/irt_core-${DAEMON_ARCH}.nexe" + case "${PLATFORM}" in windows-i686-*|*-amd64-*) - cp pepper_*"/toolchain/${NACLSDK_PLATFORM}_x86_newlib/bin/x86_64-nacl-gdb${EXE}" "${PREFIX}/nacl-gdb${EXE}" + smart_copy pepper_*"/toolchain/${NACLSDK_PLATFORM}_x86_newlib/bin/x86_64-nacl-gdb${EXE_EXT}" "${PREFIX}/nacl-gdb${EXE_EXT}" rm -rf "${PREFIX}/pnacl" patch -d pepper_*"/toolchain/${NACLSDK_PLATFORM}_pnacl/bin/pydir" \ -p1 < "${SCRIPT_DIR}/naclsdk-pydir-python3.patch" >/dev/null - cp -a pepper_*"/toolchain/${NACLSDK_PLATFORM}_pnacl" "${PREFIX}/pnacl" + smart_copy -R pepper_*"/toolchain/${NACLSDK_PLATFORM}_pnacl" "${PREFIX}/pnacl" rm -rf "${PREFIX}/pnacl/bin/"{i686,x86_64}-nacl-* rm -rf "${PREFIX}/pnacl/arm-nacl" rm -rf "${PREFIX}/pnacl/arm_bc-nacl" @@ -1049,47 +1154,57 @@ build_naclsdk() { rm -rf "${PREFIX}/pnacl/x86_64-nacl" rm -rf "${PREFIX}/pnacl/x86_64_bc-nacl" esac + case "${PLATFORM}" in - windows-i686-*) - cp pepper_*"/tools/sel_ldr_x86_64.exe" "${PREFIX}/nacl_loader-amd64.exe" - cp pepper_*"/tools/irt_core_x86_64.nexe" "${PREFIX}/irt_core-amd64.nexe" + windows-i686-*|linux-arm64-*) + smart_copy pepper_*"/tools/irt_core_x86_64.nexe" "${PREFIX}/irt_core-amd64.nexe" ;; - linux-amd64-*) - # Fix permissions on a few files which deny access to non-owner - chmod 644 "${PREFIX}/irt_core-${DAEMON_ARCH}.nexe" - ;; - linux-i686-*) - cp pepper_*"/tools/nacl_helper_bootstrap_${NACLSDK_ARCH}" "${PREFIX}/nacl_helper_bootstrap" - # Fix permissions on a few files which deny access to non-owner - chmod 644 "${PREFIX}/irt_core-${DAEMON_ARCH}.nexe" - chmod 755 "${PREFIX}/nacl_helper_bootstrap" "${PREFIX}/nacl_loader" - ;; - linux-armhf-*|linux-arm64-*) - cp pepper_*"/tools/nacl_helper_bootstrap_arm" "${PREFIX}/nacl_helper_bootstrap" + esac + + case "${PLATFORM}" in + linux-*) # Fix permissions on a few files which deny access to non-owner chmod 644 "${PREFIX}/irt_core-${DAEMON_ARCH}.nexe" - chmod 755 "${PREFIX}/nacl_helper_bootstrap" "${PREFIX}/nacl_loader" ;; esac + case "${PLATFORM}" in linux-arm64-*) - mkdir -p "${PREFIX}/lib-armhf" - cp -a pepper_*"/tools/lib/arm_trusted/lib/." "${PREFIX}/lib-armhf/." - # Copy the library loader instead of renaming it because there may still be some - # references to ld-linux-armhf.so.3 in binaries. - cp "${PREFIX}/lib-armhf/ld-linux-armhf.so.3" "${PREFIX}/lib-armhf/ld-linux-armhf" - # We can't use patchelf or 'nacl_helper_bootstrap nacl_loader' will complain: - # bootstrap_helper: nacl_loader: ELF file has unreasonable e_phnum=13 - sed -e 's|/lib/ld-linux-armhf.so.3|lib-armhf/ld-linux-armhf|' -i "${PREFIX}/nacl_loader" + chmod 644 "${PREFIX}/irt_core-amd64.nexe" ;; esac } # Only builds nacl_loader and nacl_helper_bootstrap for now, not IRT. build_naclruntime() { + local nacl_arch_list=() + case "${PLATFORM}" in + windows-amd64-*) + nacl_arch_list+=('amd64') + ;; + windows-i686-*) + nacl_arch_list+=('i686') + nacl_arch_list+=('amd64') + ;; linux-amd64-*) - local NACL_ARCH=x86-64 + nacl_arch_list+=('amd64') + ;; + linux-i686-*) + nacl_arch_list+=('i686') + ;; + linux-arm64-*) + nacl_arch_list+=('armhf') + nacl_arch_list+=('amd64') + ;; + linux-armhf-*) + nacl_arch_list+=('armhf') + ;; + macos-amd64-*) + nacl_arch_list+=('amd64') + ;; + macos-arm64-*) + nacl_arch_list+=('amd64') ;; *) log ERROR 'Unsupported platform for naclruntime' @@ -1100,14 +1215,51 @@ build_naclruntime() { local archive_name="native_client-${NACLRUNTIME_REVISION}.zip" download_extract naclruntime "${archive_name}" \ - "{$NACLRUNTIME_BASEURL}/${NACLRUNTIME_REVISION}" + "${NACLRUNTIME_BASEURL}/${NACLRUNTIME_REVISION}" "${download_only}" && return cd "${dir_name}" - env -i /usr/bin/env bash -l -c "python3 /usr/bin/scons --mode=opt-linux 'platform=${NACL_ARCH}' werror=0 sysinfo=0 sel_ldr" - cp "scons-out/opt-linux-${NACL_ARCH}/staging/nacl_helper_bootstrap" "${PREFIX}/nacl_helper_bootstrap" - cp "scons-out/opt-linux-${NACL_ARCH}/staging/sel_ldr" "${PREFIX}/nacl_loader" + + for nacl_arch in "${nacl_arch_list[@]}" + do + ( + setup_platform "${PLATFORM_SYSTEM}-${nacl_arch}-${PLATFORM_COMPILER}" + cmake_build + ) + + case "${PLATFORM}" in + linux-*) + mv "${PREFIX}/bin/nacl_helper_bootstrap" "${PREFIX}/nacl_helper_bootstrap-${nacl_arch}" + ;; + esac + + mv "${PREFIX}/bin/sel_ldr${EXE_EXT}" "${PREFIX}/nacl_loader-${nacl_arch}${EXE_EXT}" + + case "${PLATFORM}" in + linux-arm64-*) + case "${nacl_arch}" in + armhf) + local libdir_path='libs-linux-armhf' + + mkdir -p "${PREFIX}/${libdir_path}" + + smart_copy -L \ + '/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3' \ + '/lib/arm-linux-gnueabihf/libstdc++.so.6' \ + '/lib/arm-linux-gnueabihf/libc.so.6' \ + '/lib/arm-linux-gnueabihf/libm.so.6' \ + '/lib/arm-linux-gnueabihf/libgcc_s.so.1' \ + '/lib/arm-linux-gnueabihf/librt.so.1' \ + '/lib/arm-linux-gnueabihf/libpthread.so.0' \ + "${PREFIX}/${libdir_path}/" + + patchelf --set-interpreter "${libdir_path}/ld-linux-armhf.so.3" "${PREFIX}/nacl_loader-armhf" + ;; + esac + ;; + esac + done } # Check for DLL dependencies on MinGW stuff. For MSVC platforms this is bad because it should work @@ -1274,17 +1426,27 @@ build_install() { # Create a redistributable package for the dependencies build_package() { + local XZ_OPT='-9e' + cd "${WORK_DIR}" + rm -f "${PKG_BASEDIR}.tar.xz" - local XZ_OPT='-9' + case "${PLATFORM}" in windows-*-*) - tar --dereference -cvJf "${PKG_BASEDIR}.tar.xz" "${PKG_BASEDIR}" - ;; - *) - tar -cvJf "${PKG_BASEDIR}.tar.xz" "${PKG_BASEDIR}" + # Dereference symbolic links. + rm -rf "${PKG_BASEDIR}.flatten" + mv "${PKG_BASEDIR}" "${PKG_BASEDIR}.flatten" + smart_copy -RL "${PKG_BASEDIR}.flatten" "${PKG_BASEDIR}" + rm -rf "${PKG_BASEDIR}.flatten" ;; esac + + dedupe_dir "${PKG_BASEDIR}" >/dev/null + + log STATUS "Packaging ${PKG_BASEDIR}" + + tar -cvJf "${PKG_BASEDIR}.tar.xz" "${PKG_BASEDIR}" } build_wipe() { @@ -1298,22 +1460,41 @@ common_setup() { "common_setup_${1}" common_setup_arch - DOWNLOAD_DIR="${WORK_DIR}/download_cache" - PKG_BASEDIR="${PLATFORM}_${DEPS_VERSION}" - BUILD_BASEDIR="build-${PKG_BASEDIR}" - BUILD_DIR="${WORK_DIR}/${BUILD_BASEDIR}" - PREFIX="${BUILD_DIR}/prefix" - PATH="${PREFIX}/bin:${PATH}" + PLATFORM_SYSTEM="$(echo "${PLATFORM}" | cut -f1 -d-)" + PLATFORM_ARCH="$(echo "${PLATFORM}" | cut -f2 -d-)" + PLATFORM_COMPILER="$(echo "${PLATFORM}" | cut -f3 -d-)" + PLATFORM_TARGET="${PLATFORM_SYSTEM}-${PLATFORM_ARCH}" + + if "${GLOBAL_SETUP_ONCE:-true}" + then + DOWNLOAD_DIR="${WORK_DIR}/download_cache" + PKG_BASEDIR="${PLATFORM}_${DEPS_VERSION}" + BUILD_BASEDIR="build-${PKG_BASEDIR}" + BUILD_DIR="${WORK_DIR}/${BUILD_BASEDIR}" + PREFIX="${BUILD_DIR}/prefix" + NATIVE_PREFIX="${BUILD_DIR}/native-prefix" + + mkdir -p "${DOWNLOAD_DIR}" + mkdir -p "${PREFIX}/bin" + mkdir -p "${PREFIX}/include" + mkdir -p "${PREFIX}/lib" + mkdir -p "${NATIVE_PREFIX}/bin" + mkdir -p "${NATIVE_PREFIX}/include" + mkdir -p "${NATIVE_PREFIX}/lib" + + PATH="${NATIVE_PREFIX}/bin:${PATH}" + + GLOBAL_SETUP_ONCE='false' + fi + PKG_CONFIG_PATH="${PREFIX}/lib/pkgconfig:${CROSS_PKG_CONFIG_PATH}" CPPFLAGS+=" -I${PREFIX}/include" LDFLAGS+=" -L${PREFIX}/lib" - mkdir -p "${DOWNLOAD_DIR}" - mkdir -p "${PREFIX}/bin" - mkdir -p "${PREFIX}/include" - mkdir -p "${PREFIX}/lib" - - export CC CXX LD AR RANLIB STRIP PKG_CONFIG PKG_CONFIG_PATH PATH CFLAGS CXXFLAGS CPPFLAGS LDFLAGS + export PATH + export PKG_CONFIG PKG_CONFIG_PATH + export CC CXX LD AR RANLIB STRIP + export CPPFLAGS CFLAGS CXXFLAGS LDFLAGS } common_setup_arch() { @@ -1334,6 +1515,8 @@ common_setup_arch() { CFLAGS+=' -march=armv7-a -mfpu=neon' CXXFLAGS+=' -march=armv7-a -mfpu=neon' ;; + *-native-*) + ;; *) log ERROR 'Unsupported platform' ;; @@ -1355,6 +1538,7 @@ common_setup_windows() { RANLIB="${HOST}-ranlib" CFLAGS+=' -D__USE_MINGW_ANSI_STDIO=0' CMAKE_TOOLCHAIN="${SCRIPT_DIR}/../cmake/cross-toolchain-mingw${BITNESS}.cmake" + EXE_EXT='.exe' } common_setup_msvc() { @@ -1376,10 +1560,9 @@ common_setup_macos() { CC='clang' CXX='clang++' STRIP='strip' - CFLAGS+=" -arch ${MACOS_ARCH}" - CXXFLAGS+=" -arch ${MACOS_ARCH}" - LDFLAGS+=" -arch ${MACOS_ARCH}" - export CMAKE_OSX_ARCHITECTURES="${MACOS_ARCH}" + CFLAGS+=" -arch ${MACOS_ARCH} -mmacosx-version-min=${MACOS_VERSION}" + CXXFLAGS+=" -arch ${MACOS_ARCH} -mmacosx-version-min=${MACOS_VERSION}" + LDFLAGS+=" -arch ${MACOS_ARCH} -mmacosx-version-min=${MACOS_VERSION}" } common_setup_linux() { @@ -1391,8 +1574,50 @@ common_setup_linux() { CXXFLAGS+=' -fPIC' } +common_setup_native() { + case "$(uname -s)" in + CYGWIN_NT-*|MSYS_NT-*|MINGW*_NT-*) + EXE_EXT='.exe' + ;; + esac +} + +setup_default() { + # Require the compiler names to be explicitly hardcoded, we should not inherit them + # from environment as we heavily cross-compile. + export CC='false' + export CXX='false' + + # Set defaults. + export LD='ld' + export AR='ar' + export RANLIB='ranlib' + export STRIP='strip' + export PKG_CONFIG='pkg-config' + export CROSS_PKG_CONFIG_PATH='' + + LIBS_SHARED='OFF' + LIBS_STATIC='ON' + + EXE_EXT='' + + # Always reset flags, we heavily cross-compile and must not inherit any stray flag + # from environment. + export CPPFLAGS='' + export CFLAGS='-O3 -fPIC' + export CXXFLAGS='-O3 -fPIC' + export LDFLAGS='-O3 -fPIC' + + unset BITNESS + unset MACOS_ARCH + unset MACOS_VERSION + unset MACOS_HOST + unset CMAKE_TOOLCHAIN +} + # Set up environment for 32-bit i686 Windows for Visual Studio (compile all as .dll) setup_windows-i686-msvc() { + setup_default BITNESS=32 CFLAGS+=' -mpreferred-stack-boundary=2' CXXFLAGS+=' -mpreferred-stack-boundary=2' @@ -1401,80 +1626,125 @@ setup_windows-i686-msvc() { # Set up environment for 64-bit amd64 Windows for Visual Studio (compile all as .dll) setup_windows-amd64-msvc() { + setup_default BITNESS=64 common_setup msvc x86_64-w64-mingw32 } # Set up environment for 32-bit i686 Windows for MinGW (compile all as .a) setup_windows-i686-mingw() { + setup_default BITNESS=32 common_setup mingw i686-w64-mingw32 } # Set up environment for 64-bit amd64 Windows for MinGW (compile all as .a) setup_windows-amd64-mingw() { + setup_default BITNESS=64 common_setup mingw x86_64-w64-mingw32 } +setup_macos() { + MACOS_HOST="${MACOS_ARCH}-apple-macos${MACOS_VERSION}" + common_setup macos "${MACOS_HOST}" +} + # Set up environment for 64-bit amd64 macOS setup_macos-amd64-default() { - MACOS_ARCH=x86_64 + setup_default + MACOS_ARCH='x86_64' # OpenAL requires 10.14. - export MACOSX_DEPLOYMENT_TARGET=10.14 # works with CMake - common_setup macos "x86_64-apple-macos${MACOSX_DEPLOYMENT_TARGET}" + MACOS_VERSION='10.14' + setup_macos +} + +# Set up environment for 64-bit arm64 macOS +setup_macos-arm64-default() { + setup_default + MACOS_ARCH='arm64' + MACOS_VERSION='11.7' + setup_macos } # Set up environment for 32-bit i686 Linux setup_linux-i686-default() { + setup_default common_setup linux i686-unknown-linux-gnu } # Set up environment for 64-bit amd64 Linux setup_linux-amd64-default() { + setup_default common_setup linux x86_64-unknown-linux-gnu } # Set up environment for 32-bit armhf Linux setup_linux-armhf-default() { + setup_default common_setup linux arm-unknown-linux-gnueabihf } # Set up environment for 64-bit arm Linux setup_linux-arm64-default() { + setup_default common_setup linux aarch64-unknown-linux-gnu } -base_windows_amd64_msvc_packages='zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile naclsdk depcheck genlib' -all_windows_amd64_msvc_packages="${base_windows_amd64_msvc_packages}" +# Set up environment for native host tools +setup_native() { + setup_default + CC='cc' + CXX='c++' + common_setup native native +} -base_windows_i686_msvc_packages="${base_windows_amd64_msvc_packages}" -all_windows_i686_msvc_packages="${base_windows_amd64_msvc_packages}" +setup_platform() { + case "${1}" in + 'native') + export PLATFORM='native-native-native' + setup_native + ;; + *) + export PLATFORM="${1}" + "setup_${PLATFORM}" + ;; + esac +} -base_windows_amd64_mingw_packages='zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile naclsdk depcheck' +base_windows_amd64_mingw_packages='native-jwasm zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile naclsdk saigosdk naclruntime depcheck' all_windows_amd64_mingw_packages="${base_windows_amd64_mingw_packages}" base_windows_i686_mingw_packages="${base_windows_amd64_mingw_packages}" all_windows_i686_mingw_packages="${base_windows_amd64_mingw_packages}" -base_macos_amd64_default_packages='pkgconfig nasm gmp nettle sdl3 glew png jpeg webp openal ogg vorbis opus opusfile naclsdk' +base_windows_amd64_msvc_packages="${base_windows_amd64_mingw_packages} genlib" +all_windows_amd64_msvc_packages="${base_windows_amd64_msvc_packages}" + +base_windows_i686_msvc_packages="${base_windows_amd64_msvc_packages}" +all_windows_i686_msvc_packages="${base_windows_amd64_msvc_packages}" + +base_macos_arm64_default_packages='native-pkgconfig gmp nettle sdl3 glew png jpeg webp openal ogg vorbis opus opusfile naclsdk saigosdk naclruntime' +all_macos_arm64_default_packages="${base_macos_arm64_default_packages}" + +base_macos_amd64_default_packages="native-nasm ${base_macos_arm64_default_packages}" all_macos_amd64_default_packages="${base_macos_amd64_default_packages}" -base_linux_i686_default_packages='sdl3 naclsdk' -all_linux_i686_default_packages='zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile ncurses naclsdk' +base_linux_amd64_default_packages='sdl3 naclsdk saigosdk naclruntime' +all_linux_amd64_default_packages='zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile ncurses naclsdk saigosdk naclruntime' -base_linux_amd64_default_packages="${base_linux_i686_default_packages} naclruntime" -all_linux_amd64_default_packages="${all_linux_i686_default_packages} naclruntime" +base_linux_i686_default_packages="${base_linux_amd64_default_packages}" +all_linux_i686_default_packages="${all_linux_amd64_default_packages}" -base_linux_arm64_default_packages='sdl3 naclsdk' -all_linux_arm64_default_packages='zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile ncurses naclsdk' +base_linux_arm64_default_packages="${base_linux_amd64_default_packages} box64" +all_linux_arm64_default_packages="${all_linux_amd64_default_packages} box64" -base_linux_armhf_default_packages="${base_linux_arm64_default_packages}" -all_linux_armhf_default_packages="${all_linux_arm64_default_packages}" +base_linux_armhf_default_packages="${base_linux_amd64_default_packages}" +all_linux_armhf_default_packages="${all_linux_amd64_default_packages}" all_linux_platforms='linux-amd64-default linux-arm64-default linux-armhf-default linux-i686-default' all_windows_platforms='windows-amd64-mingw windows-amd64-msvc windows-i686-mingw windows-i686-msvc' -all_macos_platforms='macos-amd64-default' +all_macos_platforms='macos-amd64-default macos-arm64-default' all_platforms="${all_linux_platforms} ${all_windows_platforms} ${all_macos_platforms}" printHelp() { @@ -1498,7 +1768,7 @@ printHelp() { all linux windows macos Packages: - pkgconfig nasm zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile naclsdk wasisdk wasmtime + native-pkgconfig native-nasm native-jwasm zlib gmp nettle curl sdl3 glew png jpeg webp openal ogg vorbis opus opusfile naclsdk saigosdk naclruntime wasisdk wasmtime Virtual packages: base build packages for pre-built binaries to be downloaded when building the game @@ -1523,16 +1793,17 @@ printHelp() { base ${base_macos_amd64_default_packages} all same + macos-arm64-default: + base ${base_macos_arm64_default_packages} + all same + linux-amd64-default: + linux-i686-default: + linux-armhf-default: base ${base_linux_amd64_default_packages} all ${all_linux_amd64_default_packages} - linux-i686-default: - base ${base_linux_i686_default_packages} - all ${all_linux_i686_default_packages} - linux-arm64-default: - linux-armhf-default: base ${base_linux_arm64_default_packages} all ${all_linux_arm64_default_packages} @@ -1630,6 +1901,6 @@ esac for PLATFORM in ${platform_list} do ( - "setup_${PLATFORM}" + setup_platform "${PLATFORM}" build "${@}" ) done diff --git a/src/engine/framework/VirtualMachine.cpp b/src/engine/framework/VirtualMachine.cpp index df2739b9f3..3a05eac907 100644 --- a/src/engine/framework/VirtualMachine.cpp +++ b/src/engine/framework/VirtualMachine.cpp @@ -75,12 +75,32 @@ static Cvar::Cvar workaround_naclSystem_freebsd_disableQualification( "Disable platform qualification when running Linux NaCl loader on FreeBSD through Linuxulator", Cvar::NONE, true); +#if defined(DAEMON_NACL_BOX64_EMULATION) +#if defined(__linux__) || defined(__FreeBSD__) +#else +#error box64 is only supported on Linux or systems with a Linux compatibility layer +#endif // defined(__linux__) || defined(__FreeBSD__) +#endif // defined(DAEMON_NACL_BOX64_EMULATION)⏎ + +// Many BSDs have a Linuxulator, for now we only tested one. +#if defined(__FreeBSD__) +#define DAEMON_LINUXULATOR +#endif + +#if defined(DAEMON_NACL_RUNTIME_ENABLED) #if defined(DAEMON_NACL_BOX64_EMULATION) static Cvar::Cvar workaround_box64_disableQualification( "workaround.box64.disableQualification", "Disable platform qualification when running amd64 NaCl loader under Box64 emulation", Cvar::NONE, true); +#if defined(YOKAI_ARCH_ARM64) +static Cvar::Cvar workaround_box64_preferArmhf( + "workaround.box64.preferArmhf", + "Prefer armhf multiarch when available over Box64 emulation", + Cvar::NONE, true); +#endif + static Cvar::Cvar workaround_box64_disableBootstrap( "workaround.box64.disableBootstrap", "Disable NaCl bootstrap helper when using Box64 emulation", @@ -88,14 +108,38 @@ static Cvar::Cvar workaround_box64_disableBootstrap( static Cvar::Cvar vm_box64_path( "vm.box64.path", - "Path to the box64 binary for NaCl emulation (empty = search PATH)", + "Path to the box64 binary for NaCl emulation (empty = use provided one or search PATH if missing)", Cvar::NONE, ""); -// Resolve box64 binary path by searching PATH if not explicitly set. -static std::string ResolveBox64Path() { - std::string path = vm_box64_path.Get(); - if (!path.empty()) { - return path; +// Resolve box64 binary path by looking for a provided one or searching PATH if not explicitly set. +static std::string ResolveBox64Path(std::string naclPath) { + std::string requestedPath = vm_box64_path.Get(); + + if (requestedPath.empty()) { + std::string providedPath = FS::Path::Build(naclPath, "box64"); + + if (FS::RawPath::FileExists(providedPath)) { + std::string libDirPath = FS::Path::Build(naclPath, "libs-linux-amd64"); + std::string libPath = FS::Path::Build(libDirPath, "libgcc_s.so.1"); + + if (FS::RawPath::FileExists(libPath)) { + Sys::SetEnv("BOX64_LD_LIBRARY_PATH", libDirPath.c_str()); + } + else { + Log::Warn("Using provided Box64 executable but the libraries are missing."); + } + + return providedPath; + } + + Log::Warn("Box64 emulation is enabled but the executable is not provided with the engine: %s", providedPath); + } + + if (!FS::RawPath::FileExists(requestedPath)) { + Sys::Error("Box64 emulation is enabled but the requested executable is missing: %s", requestedPath); + } + else { + return requestedPath; } const char* envPath = getenv("PATH"); @@ -121,34 +165,43 @@ static std::string ResolveBox64Path() { "Install Box64 or set vm.box64.path to the full path of the box64 binary."); return ""; // unreachable } -#endif - -static Cvar::Cvar vm_nacl_qualification( - "vm.nacl.qualification", - "Enable NaCl loader platform qualification", - Cvar::INIT, true); - -static Cvar::Cvar vm_nacl_bootstrap( - "vm.nacl.bootstrap", - "Use NaCl bootstrap helper", - Cvar::INIT, true); - -static Cvar::Cvar vm_timeout( - "vm.timeout", - "Receive timeout in seconds", - Cvar::NONE, 2); +#endif // DAEMON_NACL_BOX64_EMULATION +#endif // DAEMON_NACL_RUNTIME_ENABLED #if defined(DAEMON_NACL_RUNTIME_ENABLED) static Cvar::Cvar vm_nacl_available( "vm.nacl.available", "Whether NaCl runtime is available on this platform", Cvar::ROM, true); -#else +#else // !defined(DAEMON_NACL_RUNTIME_ENABLED) static Cvar::Cvar vm_nacl_available( "vm.nacl.available", "Whether NaCl runtime is available on this platform", Cvar::ROM, false); -#endif +#endif // !defined(DAEMON_NACL_RUNTIME_ENABLED) + +#if defined(DAEMON_NACL_RUNTIME_ENABLED) +static Cvar::Cvar vm_timeout( + "vm.timeout", + "Receive timeout in seconds", + Cvar::NONE, 2); + +static Cvar::Cvar vm_nacl_qualification( + "vm.nacl.qualification", + "Enable NaCl loader platform qualification", + Cvar::INIT, true); + +#if defined(__linux__) || defined(DAEMON_LINUXULATOR) +#define DAEMON_NACL_BOOSTRAP_ENABLED +#endif // defined(__linux__) || defined(DAEMON_LINUXULATOR) + +#if defined(DAEMON_NACL_BOOSTRAP_ENABLED) +static Cvar::Cvar vm_nacl_bootstrap( + "vm.nacl.bootstrap", + "Use NaCl bootstrap helper", + Cvar::INIT, true); +#endif // defined(DAEMON_NACL_BOOSTRAP_ENABLED) +#endif // defined(DAEMON_NACL_RUNTIME_ENABLED) namespace VM { @@ -300,36 +353,242 @@ static std::pair InternalLoadModule(std::pair(probe.data()), + nullptr, + }; + + execve(probe.data(), argv, environ); + + switch (errno) + { + case ENOEXEC: + // Kernel cannot execute the probe. + _exit(100); + + case ENOENT: + case EACCES: + // Missing or inaccessible probe. + _exit(101); + + default: + _exit(102); + } + } + + int status; + if (waitpid(pid, &status, 0) < 0) { + return ArmhfSupport::Unknown; + } + + if (!WIFEXITED(status)) { + return ArmhfSupport::Unknown; + } + + switch (WEXITSTATUS(status)) + { + case 100: + return ArmhfSupport::Unsupported; + + case 101: + case 102: + return ArmhfSupport::Unknown; + + default: + // The execve() call succeeded, so the probe has been executed properly. + return ArmhfSupport::Supported; + } +} +#endif // NACL_ARCH_ARM64 +#endif // defined(__linux__) || defined(DAEMON_LINUXULATOR) + static std::pair CreateNaClVM(std::pair pair, Str::StringRef name, bool debug, bool extract, int debugLoader) { CheckMinAddressSysctlTooLarge(); const std::string& libPath = FS::GetLibPath(); -#ifdef DAEMON_NACL_RUNTIME_PATH +#if defined(DAEMON_NACL_RUNTIME_PATH) const char* naclPath = DAEMON_NACL_RUNTIME_PATH_STRING; -#else +#else // !defined(DAEMON_NACL_RUNTIME_PATH) const std::string& naclPath = libPath; -#endif +#endif // !defined(DAEMON_NACL_RUNTIME_PATH) std::vector args; char rootSocketRedir[32]; - std::string module, nacl_loader, irt, bootstrap, modulePath, verbosity; - FS::File stderrRedirect; + std::string module, nacl_loader, irt, arch, modulePath, verbosity; + +#if defined(DAEMON_NACL_BOOSTRAP_ENABLED) + std::string bootstrapPath; +#endif + #if defined(DAEMON_NACL_BOX64_EMULATION) std::string box64Path; - bool usingBox64 = false; #endif -#if !defined(_WIN32) || defined(_WIN64) - constexpr bool win32Force64Bit = false; + + FS::File stderrRedirect; + + bool inheritEnvironment = false; + +#if defined(DAEMON_NACL_BOOSTRAP_ENABLED) + constexpr bool hasBootstrap = true; #else + constexpr bool hasBootstrap = false; +#endif + +#if defined(__linux__) || defined(DAEMON_LINUXULATOR) +#if defined(DAEMON_NACL_BOX64_EMULATION) + constexpr bool hasBox64 = true; +#else // !defined(DAEMON_NACL_BOX64_EMULATION) + constexpr bool hasBox64 = false; +#endif // !defined(DAEMON_NACL_BOX64_EMULATION) + +#if defined(YOKAI_ARCH_ARM64) + constexpr bool hasLdArmhf = true; +#else // !defined(YOKAI_ARCH_ARM64) + constexpr bool hasLdArmhf = false; +#endif // !defined(YOKAI_ARCH_ARM64) +#else // !( defined(__linux__) || defined(DAEMON_LINUXULATOR) ) + constexpr bool hasBox64 = false; + constexpr bool hasLdArmhf = false; +#endif // !( defined(__linux__) || defined(DAEMON_LINUXULATOR) ) + +#if !defined(_WIN32) || defined(_WIN64) + constexpr bool i686ForceAmd64 = false; +#else // !( !defined(_WIN32) || defined(_WIN64) ) // On Windows, even if we are running a 32-bit engine, we must use the // 64-bit nacl_loader if the host operating system is 64-bit. SYSTEM_INFO systemInfo; GetNativeSystemInfo(&systemInfo); - const bool win32Force64Bit = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; + constexpr bool i686ForceAmd64 = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; +#endif // !( !defined(_WIN32) || defined(_WIN64) ) + +#if defined(YOKAI_ARCH_ARM64) + /* When we will have implemented box64 integration for arm64, and once we + will have implemented the detection of armhf support being provided, we + will be able to turn this boolean on based on such detection. */ + bool hasArmhf = true; +#else + bool hasArmhf = false; +#endif + + // Only use armhf on arm64 when the hardware can do 32-bit. + bool useLdArmhf = hasLdArmhf && hasArmhf; + +#if defined(__linux__) || defined(DAEMON_LINUXULATOR) +#if defined(YOKAI_ARCH_ARM64) + std::string ldLoaderPath = FS::Path::Build(libPath, "libs-linux-armhf"); + ldLoaderPath = FS::Path::Build(ldLoaderPath, "ld-linux-armhf.so.3"); + + switch (CheckArmhfSupport(ldLoaderPath)) + { + case ArmhfSupport::Supported: + Log::Notice("Working armhf multiarch support."); + break; + + case ArmhfSupport::Unsupported: + Log::Notice("Unsupported armhf multiarch."); + useLdArmhf = false; + break; + + case ArmhfSupport::Unknown: + Log::Warn("Could not determine armhf multiarch support."); + useLdArmhf = false; + break; + } + + if (useLdArmhf) { + if (!workaround_box64_preferArmhf.Get()) { + useLdArmhf = false; + } + else { + Log::Notice("Preferring armhf multiarch over Box64 emulation."); + } + } +#endif // defined(YOKAI_ARCH_ARM64) +#endif // defined(__linux__) || defined(DAEMON_LINUXULATOR) + + // Only use rbox64 on arm64 when the hardware cannot do 32-bit. + bool useBox64 = hasBox64 && !useLdArmhf; + + bool useBootstrap = hasBootstrap; + +#if defined(DAEMON_NACL_BOOSTRAP_ENABLED) + if (hasBootstrap) { + if (!vm_nacl_bootstrap.Get()) { + useBootstrap = false; + } + +#if defined(DAEMON_NACL_BOX64_EMULATION) + /* Use Box64 to run the x86_64 NaCl loader on non-x86 architectures. + The bootstrap helper uses a double-exec pattern that Box64 cannot handle, + so we skip it and prepend "box64" to the nacl_loader command instead. */ + if (useBootstrap + && useBox64 + && workaround_box64_disableBootstrap.Get()) { + useBootstrap = false; + } +#endif // defined(DAEMON_NACL_BOX64_EMULATION) + } +#endif // defined(DAEMON_NACL_BOOSTRAP_ENABLED) + + if (useLdArmhf) { + arch = "armhf"; + } + else if (useBox64 || i686ForceAmd64) { + arch = "amd64"; + } + else { + arch = DAEMON_NACL_ARCH_STRING; + } + + module = Str::Format("%s-%s.nexe", name, arch); + irt = FS::Path::Build(naclPath, Str::Format("irt_core-%s.nexe", arch)); + nacl_loader = FS::Path::Build(naclPath, Str::Format("nacl_loader-%s%s", arch, EXE_EXT)); + +#if defined(DAEMON_NACL_BOOSTRAP_ENABLED) + if (useBootstrap) { + if (useLdArmhf) { + bootstrapPath = FS::Path::Build(naclPath, Str::Format("nacl_helper_bootstrap-ldarmhf")); + } + else { + bootstrapPath = FS::Path::Build(naclPath, Str::Format("nacl_helper_bootstrap-%s", arch)); + } + } #endif // Extract the nexe from the pak so that nacl_loader can load it - module = win32Force64Bit - ? name + "-amd64.nexe" - : Str::Format("%s-%s.nexe", name, DAEMON_NACL_ARCH_STRING); if (extract) { try { FS::File out = FS::HomePath::OpenWrite(module); @@ -347,10 +606,6 @@ static std::pair CreateNaClVM(std::pair CreateNaClVM(std::pair Error while loading "sgame-armhf.nexe": CPU model is not supported + > Error while loading "sgame-armhf.nexe": CPU model is not supported - From nacl_loader --help we can read: + From nacl_loader --help we can read: - > -Q disable platform qualification (dangerous!) + > -Q disable platform qualification (dangerous!) - When this option is enabled, nacl_loader will print: + When this option is enabled, nacl_loader will print: - > PLATFORM QUALIFICATION DISABLED BY -Q - Native Client's sandbox will be unreliable! + > PLATFORM QUALIFICATION DISABLED BY -Q - Native Client's sandbox will be unreliable! - But the nexe will load and run. */ + But the nexe will load and run. */ - if (onArm64) { - Log::Warn("Disabling NaCL platform qualification on arm64 kernel architecture."); - enableQualification = false; - } + if (onArm64) { + Log::Warn("Disabling NaCl platform qualification on arm64 kernel architecture."); + enableQualification = false; } -#endif + } +#endif // defined(__linux__) && (defined(YOKAI_ARCH_ARM64) || defined(YOKAI_ARCH_ARMHF)) + +#if defined(DAEMON_NACL_BOX64_EMULATION) + if (enableQualification + && useBox64 + && workaround_box64_disableQualification.Get()) { + /* When running the amd64 NaCl loader under Box64, the loader's + platform qualification will fail because the CPU is not actually x86_64. + Disabling qualification allows the emulated loader to proceed. */ + + Log::Warn("Disabling NaCl platform qualification for Box64 emulation."); + enableQualification = false; + } +#endif // defined(DAEMON_NACL_BOX64_EMULATION) #if defined(__FreeBSD__) + if (enableQualification + && workaround_naclSystem_freebsd_disableQualification.Get()) { /* While it is possible to build a native FreeBSD engine, the only available NaCl loader is the Linux one, which can run on Linuxulator (the FreeBSD Linux compatibility layer). @@ -466,26 +721,10 @@ static std::pair CreateNaClVM(std::pair CreateNaClVM(std::pair CreateNativeVM(std::pair pair, Str::StringRef name, bool debug) { const std::string& libPath = FS::GetLibPath(); @@ -622,7 +858,9 @@ void VMBase::Create() } #endif if (type == TYPE_NACL || type == TYPE_NACL_LIBPATH) { +#if defined(DAEMON_NACL_RUNTIME_ENABLED) std::tie(processHandle, rootSocket) = CreateNaClVM(std::move(pair), name, params.debug.Get(), type == TYPE_NACL, params.debugLoader.Get()); +#endif // defined(DAEMON_NACL_RUNTIME_ENABLED) } else if (type == TYPE_NATIVE_EXE) { std::tie(processHandle, rootSocket) = CreateNativeVM(std::move(pair), name, params.debug.Get()); } else { diff --git a/tools/nacl_helper_bootstrap-armhf/nacl_helper_bootstrap-armhf.cpp b/tools/nacl_helper_bootstrap-ldarmhf/nacl_helper_bootstrap-ldarmhf.cpp similarity index 92% rename from tools/nacl_helper_bootstrap-armhf/nacl_helper_bootstrap-armhf.cpp rename to tools/nacl_helper_bootstrap-ldarmhf/nacl_helper_bootstrap-ldarmhf.cpp index ec16447482..b95dbcd0ee 100644 --- a/tools/nacl_helper_bootstrap-armhf/nacl_helper_bootstrap-armhf.cpp +++ b/tools/nacl_helper_bootstrap-ldarmhf/nacl_helper_bootstrap-ldarmhf.cpp @@ -44,19 +44,19 @@ int main(int argc, char *argv[]) { return err; } - err = putenv(strdup("LD_LIBRARY_PATH=lib-armhf")); + err = putenv(strdup("LD_LIBRARY_PATH=libs-linux-armhf")); if (err != 0) { return err; } - char *helper = strdup("./nacl_helper_bootstrap"); + char *helper = strdup("./nacl_helper_bootstrap-armhf"); argv[0] = helper; execv(helper, argv); // The execv() function returns only if an error has occurred. - printf("nacl_helper_bootstrap-armhf: %s\n", strerror(errno)); + printf("nacl_helper_bootstrap-ldarmhf: %s\n", strerror(errno)); return 1; }