diff --git a/.gitignore b/.gitignore index 00e20db8da..b753d1cf66 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ build #ignore external deps external_deps/* !external_deps/build.sh +!external_deps/sdk-build.sh !external_deps/cygtar.py !external_deps/*.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index 65ff1a430b..47797591c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,15 @@ if (Daemon_OUT) endif() include(Yokai/All) -include(DaemonNaclHost) + +if (NOT YOKAI_TARGET_SYSTEM_NACL) + 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}\"") +endif() ################################################################################ # Configuration options @@ -189,8 +197,9 @@ else() set(FULL_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}) endif() -# Dependencies version, this must match the number in external_deps/build.sh -set(DEPS_VERSION 11) +# Dependencies versions +set(DEPS_VERSION 11) # This must match the number in external_deps/build.sh +set(SAIGOSDK_VERSION 20260925) # This must match the number in external_deps/sdk-build.sh option(USE_EXTERNAL_DEPS "Download or reuse dependencies from EXTERNAL_DEPS_DIR (mandatory for building and running NaCl .nexe binaries)." ON) @@ -265,6 +274,9 @@ endif() option(USE_EXTERNAL_DEPS_LIBS "Build and link against libraries from the EXTERNAL_DEPS_DIR" ${DEFAULT_USE_EXTERNAL_DEPS_LIBS}) +set(PNACL_SDK_PREFIX "${DEPS_DIR}/pnacl" CACHE PATH "PNaCl SDK path") +mark_as_advanced(PNACL_SDK_PREFIX) + if (USE_EXTERNAL_DEPS AND NOT YOKAI_TARGET_SYSTEM_NACL) if (DEPS_DIR) message(STATUS "Using external deps dir: ${DEPS_DIR}") @@ -291,6 +303,7 @@ endif() # meaning we have to detect useless engine compiler to set # useless engine flags when only building vms. include(DaemonFlags) +include(DaemonNaclFlags) # FIXME: Once engine flags would be only set when building the engine # this would be likely unused by vms as they are built by DaemonGame. @@ -397,33 +410,33 @@ if (DEPS_DIR) if (NOT EXISTS ${DEPS_DIR}) file(MAKE_DIRECTORY ${EXTERNAL_DEPS_DIR}) get_filename_component(BASENAME ${DEPS_DIR} NAME) - set(DEPS_FILENAME "${BASENAME}${DEPS_EXT}") - - # Download test DEPS archive if DEPS archive isn't available yet. - # This makes possible to get the CI working before releasing the DEPS archive. - foreach(REMOTE_BASEURL https://dl.unvanquished.net/deps;https://dl.unvanquished.net/test/deps) - set(REMOTE "${REMOTE_BASEURL}/${DEPS_FILENAME}") - message(STATUS "Downloading dependencies from '${REMOTE}'") - - file(DOWNLOAD "${REMOTE}" "${OBJ_DIR}/${DEPS_FILENAME}" - SHOW_PROGRESS - STATUS DOWNLOAD_RESULT - LOG DOWNLOAD_LOG - ) - - list(GET DOWNLOAD_RESULT 0 DOWNLOAD_STATUS) - list(GET DOWNLOAD_RESULT 1 DOWNLOAD_STRING) - - if (DOWNLOAD_STATUS EQUAL 0) - break() - else () - message(WARNING "Error downloading '${REMOTE}': - Status code: ${DOWNLOAD_STATUS} - Error string: ${DOWNLOAD_STRING} - Download log: ${DOWNLOAD_LOG}" - ) - endif() - endforeach() + set(DEPS_FILENAME "${BASENAME}${DEPS_EXT}") + + # Download test DEPS archive if DEPS archive isn't available yet. + # This makes possible to get the CI working before releasing the DEPS archive. + foreach(REMOTE_BASEURL https://dl.unvanquished.net/deps;https://dl.unvanquished.net/test/deps) + set(REMOTE "${REMOTE_BASEURL}/${DEPS_FILENAME}") + message(STATUS "Downloading dependencies from '${REMOTE}'") + + file(DOWNLOAD "${REMOTE}" "${OBJ_DIR}/${DEPS_FILENAME}" + SHOW_PROGRESS + STATUS DOWNLOAD_RESULT + LOG DOWNLOAD_LOG + ) + + list(GET DOWNLOAD_RESULT 0 DOWNLOAD_STATUS) + list(GET DOWNLOAD_RESULT 1 DOWNLOAD_STRING) + + if (DOWNLOAD_STATUS EQUAL 0) + break() + else () + message(WARNING "Error downloading '${REMOTE}': + Status code: ${DOWNLOAD_STATUS} + Error string: ${DOWNLOAD_STRING} + Download log: ${DOWNLOAD_LOG}" + ) + endif() + endforeach() if (NOT DOWNLOAD_STATUS EQUAL 0) message(FATAL_ERROR "Failed to download '${DEPS_FILENAME}'") @@ -442,6 +455,11 @@ if (DEPS_DIR) endif() endif() + if (BUILD_GAME_NACL AND USE_NACL_SAIGO AND NOT SAIGOSDK_PREFIX) + include(DaemonDependenciesDownload) + download_saigosdk() + endif() + if (USE_EXTERNAL_DEPS_LIBS) # Add to paths set(CMAKE_FIND_ROOT_PATH ${DEPS_DIR} ${CMAKE_FIND_ROOT_PATH}) @@ -462,7 +480,6 @@ endif() # LIBS_BASE, LIBS_ENGINE_BASE LIBS_ENGINE, LIBS_BASECLIENT, LIBS_CLIENT # Native client -include(DaemonNacl) if (YOKAI_TARGET_SYSTEM_NACL) add_library(srclibs-nacl-module EXCLUDE_FROM_ALL ${NACLLIST_MODULE}) set(LIBS_BASE ${LIBS_BASE} srclibs-nacl-module) @@ -483,16 +500,6 @@ elseif (YOKAI_TARGET_SYSTEM_NACL) find_library(NACL_EXCEPTION nacl_exception) find_library(NACL_MINIDUMP minidump_generator) - # HACK: To be removed when Saigo is repackaged properly. - if (NOT NACL_MINIDUMP - # NACL_TARGET is specific to Saigo, PNaCl target is le32 and doesn't set NACL_TARGET. - AND "${NACL_TARGET}" STREQUAL "i686" - # x86_64-nacl/lib32 is specific to Google build, other builds may provide i686-nacl/lib instead. - AND EXISTS "${DEPS_DIR}/saigo_newlib/x86_64-nacl/lib32") - set(NACL_EXCEPTION "${DEPS_DIR}/saigo_newlib/x86_64-nacl/lib32/libnacl_exception.a") - set(NACL_MINIDUMP "${DEPS_DIR}/saigo_newlib/x86_64-nacl/lib32/libminidump_generator.a") - endif() - set(LIBS_BASE ${LIBS_BASE} ${NACL_MINIDUMP} ${NACL_EXCEPTION}) else() find_library(LIBM m) @@ -969,56 +976,49 @@ 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} - ) - - 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 - ) - - # 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) - + foreach(arch_name IN LISTS DAEMON_NACL_ARCH_NAME_LIST) + # The NaCl loader and IRT are required to load .nexe files + if (YOKAI_TARGET_SYSTEM_WINDOWS AND YOKAI_TARGET_ARCH_I686 AND "${arch_name}" STREQUAL "amd64") + # Backport compatibility until the external_deps script properly suffixes names in the archives. add_custom_command(TARGET runtime_deps PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - ${FULL_OUTPUT_DIR}/lib-armhf + 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} ) - + else() 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_loader${CMAKE_EXECUTABLE_SUFFIX} + ${FULL_OUTPUT_DIR}/nacl_loader-${arch_name}${CMAKE_EXECUTABLE_SUFFIX} ) endif() 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 + ${DEPS_DIR}/irt_core-${arch_name}.nexe + ${FULL_OUTPUT_DIR}/irt_core-${arch_name}.nexe ) - endif() + endforeach() - # 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 - ) + if (YOKAI_TARGET_SYSTEM_LINUX_COMPATIBILITY) + if (DAEMON_NACL_MULTIARCH) + add_custom_command(TARGET runtime_deps PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${DEPS_DIR}/libs-${DAEMON_NACL_ARCH_NAME} + ${FULL_OUTPUT_DIR}/libs-linux-${DAEMON_NACL_ARCH_NAME} + ) + endif() + + # Linux uses a bootstrap program to reserve address space for 32-bit runtimes. + foreach(arch_name IN LISTS DAEMON_NACL_ARCH_NAME_LIST) + if ("${arch_name}" IN_LIST "i686;armhf") + 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-${arch_name} + ) + endif() + endforeach() endif() # Mac requires some libraries from external_deps diff --git a/cmake/DaemonDependenciesDownload.cmake b/cmake/DaemonDependenciesDownload.cmake new file mode 100644 index 0000000000..2313300d3e --- /dev/null +++ b/cmake/DaemonDependenciesDownload.cmake @@ -0,0 +1,74 @@ +# Daemon BSD Source Code +# Copyright (c) 2013-2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# TODO: Move other deps downloading code in here. + +set(SAIGOSDK_BASENAME "saigosdk-${DEPS_SYSTEM}-${DEPS_ARCH}_${SAIGOSDK_VERSION}") + +# Warning: changing SAIGOSDK_PREFIX/SAIGOSDK_VERSION after subprojects have been configured WILL +# change the compiler, but it is a bad idea since flag tests and such (not to mention the actual +# compiled artifacts) will be out of date. +set(SAIGOSDK_PREFIX "${EXTERNAL_DEPS_DIR}/${SAIGOSDK_BASENAME}" CACHE PATH "PNaCl SDK path") +mark_as_advanced(SAIGOSDK_PREFIX) + +# As an alternative to downloading, external_deps/sdk-build.sh can be used, to build the host-mode +# dependencies and install them in the expected path. +function(download_saigosdk) + if (NOT EXISTS "${SAIGOSDK_PREFIX}") + set(DEPS_FILENAME "${SAIGOSDK_BASENAME}.tar.xz") + set(REMOTE "https://github.com/DaemonEngine/saigo-nacl-sdk/releases/download/v${SAIGOSDK_VERSION}/${DEPS_FILENAME}") + message(STATUS "Downloading NaCl SDK from '${REMOTE}'") + + file(DOWNLOAD "${REMOTE}" "${OBJ_DIR}/${DEPS_FILENAME}" + SHOW_PROGRESS + STATUS DOWNLOAD_RESULT + LOG DOWNLOAD_LOG + ) + + list(GET DOWNLOAD_RESULT 0 DOWNLOAD_STATUS) + list(GET DOWNLOAD_RESULT 1 DOWNLOAD_STRING) + + if (NOT DOWNLOAD_STATUS EQUAL 0) + message(FATAL_ERROR "Failed to download '${REMOTE}': This may be a network error, or your system may be an unsupported host platform. + Status code: ${DOWNLOAD_STATUS} + Error string: ${DOWNLOAD_STRING} + Download log: ${DOWNLOAD_LOG}" + ) + endif() + + message(STATUS "SDK download completed successfully") + + # Extract the downloaded archive + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xJf ${OBJ_DIR}/${DEPS_FILENAME} + WORKING_DIRECTORY ${EXTERNAL_DEPS_DIR} + RESULT_VARIABLE EXTRACT_RESULT + ) + if (NOT EXTRACT_RESULT EQUAL 0) + message(FATAL_ERROR "Could not extract ${DEPS_FILENAME}") + endif() + endif() +endfunction() diff --git a/cmake/DaemonFlags.cmake b/cmake/DaemonFlags.cmake index 179835ddca..f999e5e272 100644 --- a/cmake/DaemonFlags.cmake +++ b/cmake/DaemonFlags.cmake @@ -260,10 +260,14 @@ if (USE_FLOAT_EXCEPTIONS) add_definitions(-DDAEMON_USE_FLOAT_EXCEPTIONS) endif() -if (NOT NACL AND BUILD_CLIENT) +if (NOT YOKAI_TARGET_SYSTEM_NACL AND BUILD_CLIENT) option(USE_OPENMP "Use OpenMP to parallelize some tasks" OFF) endif() +if (NOT YOKAI_TARGET_SYSTEM_NACL AND BUILD_CLIENT AND USE_OPENMP) + set(ENABLE_OPENMP ON) +endif() + if (YOKAI_CXX_COMPILER_MSVC_COMPATIBILITY) if (YOKAI_CXX_COMPILER_MSVC) # /MP doesn't do anything and prints a warning in the Clang clone. @@ -275,7 +279,7 @@ if (YOKAI_CXX_COMPILER_MSVC_COMPATIBILITY) set_cxx_flag("/std:c++23preview") endif() - if (NOT NACL AND BUILD_CLIENT AND USE_OPENMP) + if (ENABLE_OPENMP) # Flag checks doen't work with MSVC so we assume it's there. set(OPENMP_COMPILE_FLAG "/openmp") endif() @@ -385,7 +389,7 @@ else() endif() endif() - if (NOT NACL AND BUILD_CLIENT AND USE_OPENMP) + if (ENABLE_OPENMP) check_CXX_compiler_flag("-fopenmp" FLAG_FOPENMP) if (FLAG_FOPENMP) @@ -396,7 +400,7 @@ else() endif() endif() - if (YOKAI_TARGET_SYSTEM_NACL AND USE_NACL_SAIGO AND DAEMON_NACL_ARCH_ARMHF) + if (YOKAI_TARGET_SYSTEM_NACL AND YOKAI_CXX_COMPILER_SAIGO AND YOKAI_TARGET_ARCH_ARMHF) # Saigo produces broken arm builds when optimizing them. # See: https://github.com/Unvanquished/Unvanquished/issues/3297 # When setting this clang-specific option, we don't have to care @@ -445,7 +449,7 @@ else() try_flag(WARNINGS "-Werror") endif() - if (YOKAI_TARGET_SYSTEM_NACL AND NOT USE_NACL_SAIGO) + if (YOKAI_TARGET_SYSTEM_NACL AND YOKAI_CXX_COMPILER_PNACL) # PNaCl only supports libc++ as standard library. set_c_cxx_flag("-stdlib=libc++") set_c_cxx_flag("--pnacl-allow-exceptions") @@ -508,7 +512,7 @@ else() # Don't set _FORTIFY_SOURCE in debug builds. endif() - if (NOT NACL) + if (NOT YOKAI_TARGET_SYSTEM_NACL) # Saigo reports weird errors when building some cgame and sgame arm nexe with PIC: # > error: Cannot represent a difference across sections # > error: expected relocatable expression diff --git a/cmake/DaemonGame.cmake b/cmake/DaemonGame.cmake index f6adde3c7c..3e79b0b96f 100644 --- a/cmake/DaemonGame.cmake +++ b/cmake/DaemonGame.cmake @@ -44,9 +44,9 @@ include(Yokai/All) # Do not report unused native compiler if native vms are not built. # If only NACL vms are built, this will be reported in chainloaded build. -if (BUILD_GAME_NATIVE_DLL OR BUILD_GAME_NATIVE_EXE OR NACL) - include(DaemonNacl) +if (BUILD_GAME_NATIVE_DLL OR BUILD_GAME_NATIVE_EXE OR GAME_BUILD_SUBINVOCATION) include(DaemonFlags) + include(DaemonNaclFlags) endif() # Source lists for src/shared @@ -68,39 +68,61 @@ set(SHAREDLIST_sgame # Function to setup all the Sgame/Cgame libraries include(CMakeParseArguments) -# The NaCl SDK only runs on amd64 or i686. -if (NOT FORK EQUAL 2) - if (CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME +list(APPEND NACL_ALL_TARGETS "amd64" "i686" "armhf") + +if (NOT GAME_BUILD_SUBINVOCATION) + option(USE_NACL_SAIGO "Use the Saigo toolchain to build NaCl executables" OFF) + + 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() + + list(APPEND NACL_ALL_TARGETS "amd64" "i686" "armhf") + + 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) - set(NACL_ALL_TARGETS "amd64;i686;armhf") - set(BUILD_GAME_NACL_TARGETS "all" CACHE STRING "Enabled NaCl \"nexe\" architecture targets, values: ${NACL_ALL_TARGETS}, all, native, none.") + set(BUILD_GAME_NACL_TARGETS "all" CACHE STRING "Enabled NaCl \"nexe\" architecture targets, values: ${NACL_ALL_TARGETS};all;native;none") mark_as_advanced(BUILD_GAME_NACL_TARGETS) - if (BUILD_GAME_NACL_TARGETS STREQUAL "all") - set(NACL_TARGETS "${NACL_ALL_TARGETS}") - elseif (BUILD_GAME_NACL_TARGETS STREQUAL "native") - set(NACL_TARGETS "${YOKAI_TARGET_ARCH_NAME}") - elseif (BUILD_GAME_NACL_TARGETS STREQUAL "none") - set(NACL_TARGETS "") - else() - set(NACL_TARGETS "${BUILD_GAME_NACL_TARGETS}") - endif() + if (BUILD_GAME_NACL) + foreach(nacl_target ${BUILD_GAME_NACL_TARGETS}) + if ("${nacl_target}" STREQUAL "all") + list(APPEND nacl_target_list ${NACL_ALL_TARGETS}) + elseif ("${nacl_target}" STREQUAL "native") + list(APPEND nacl_target_list "${YOKAI_TARGET_ARCH_NAME}") + elseif ("${nacl_target}" STREQUAL "none") + set(nacl_target_list "") + else() + list(APPEND nacl_target_list "${nacl_target}") + endif() + endforeach() + + foreach(nacl_target IN LISTS nacl_target_list) + daemon_detect_nacl_arch("${nacl_target}") + + foreach(detected_target IN LISTS DAEMON_NACL_ARCH_NAME_LIST) + if (NOT "${detected_target}" IN_LIST NACL_TARGETS) + list(APPEND NACL_TARGETS "${detected_target}") + endif() + endforeach() + endforeach() - foreach(NACL_TARGET ${NACL_TARGETS}) - set(IS_NACL_VALID_TARGET OFF) - foreach(NACL_VALID_TARGET ${NACL_ALL_TARGETS}) - if(NACL_TARGET STREQUAL NACL_VALID_TARGET) - set(IS_NACL_VALID_TARGET ON) + foreach(nacl_target IN LISTS NACL_TARGETS) + if (NOT nacl_target IN_LIST NACL_ALL_TARGETS) + message(FATAL_ERROR "Invalid NaCl target ${nacl_target}, must be one of ${NACL_ALL_TARGETS}") endif() endforeach() - if (NOT IS_NACL_VALID_TARGET) - message(FATAL_ERROR "Invalid NaCl target ${NACL_TARGET}, must be one of ${NACL_ALL_TARGETS}") - endif() - endforeach() + message(STATUS "Building NaCl targets: ${NACL_TARGETS}") + endif() else() set(BUILD_GAME_NACL OFF) set(NACL_TARGETS "") @@ -134,7 +156,7 @@ function(buildGameModule module_slug) if (module_slug STREQUAL "nacl") set_target_properties(${module_target} PROPERTIES OUTPUT_NAME "${GAMEMODULE_NAME}" - SUFFIX "${PLATFORM_EXE_SUFFIX}") + SUFFIX "${NACL_EXECUTABLE_SUFFIX}") target_link_libraries(${module_target} ${GAMEMODULE_LIBS} ${LIBS_BASE}) else() @@ -150,13 +172,13 @@ function(gameSubProject) BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${NACL_VMS_PROJECT} CMAKE_GENERATOR ${VM_GENERATOR} CMAKE_ARGS - -DFORK=2 - -DDAEMON_DIR=${Daemon_SOURCE_DIR} - -DDEPS_DIR=${DEPS_DIR} + "-DDAEMON_DIR=${Daemon_SOURCE_DIR}" + "-DDEPS_DIR=${DEPS_DIR}" -DBUILD_CLIENT=OFF -DBUILD_TTY_CLIENT=OFF -DBUILD_SERVER=OFF - -DBUILD_DUMMY_GAMELOGIC=${BUILD_DUMMY_GAMELOGIC} + "-DBUILD_DUMMY_GAMELOGIC=${BUILD_DUMMY_GAMELOGIC}" + -DGAME_BUILD_SUBINVOCATION=ON ${ARGV} ${INHERITED_OPTION_ARGS} INSTALL_COMMAND "" @@ -186,8 +208,9 @@ function(GAMEMODULE) buildGameModule("native-exe") endif() - if (NOT FORK) # create the nacl-vms target only the first time that GAMEMODULE is called - set(FORK 1 PARENT_SCOPE) + if (NOT NACL_VMS_TARGET_CREATED AND NOT GAME_BUILD_SUBINVOCATION) + # Create the nacl-vms target only the first time that GAMEMODULE is called. + set(NACL_VMS_TARGET_CREATED ON PARENT_SCOPE) if (CMAKE_GENERATOR MATCHES "Visual Studio") set(VM_GENERATOR "NMake Makefiles") @@ -202,37 +225,40 @@ function(GAMEMODULE) "-D${inherited_option}=${${inherited_option}}") endforeach(inherited_option) - if (BUILD_GAME_NACL) + if (BUILD_GAME_NACL AND NOT YOKAI_TARGET_SYSTEM_NACL) if (USE_NACL_SAIGO) + if (NOT IS_DIRECTORY "${SAIGOSDK_PREFIX}") + message(FATAL_ERROR "SAIGOSDK_PREFIX configured as '${SAIGOSDK_PREFIX}' which is not an existing directory") + endif() + add_custom_target(nacl-vms ALL) unset(NACL_VMS_PROJECTS) - foreach(NACL_TARGET ${NACL_TARGETS}) - if (NACL_TARGET STREQUAL "i686") - set(SAIGO_ARCH "i686") - elseif (NACL_TARGET STREQUAL "amd64") - set(SAIGO_ARCH "x86_64") - elseif (NACL_TARGET STREQUAL "armhf") - set(SAIGO_ARCH "arm") - else() + foreach(nacl_target IN LISTS NACL_TARGETS) + if (NOT nacl_target IN_LIST NACL_ALL_TARGETS) message(FATAL_ERROR "Unknown NaCl architecture ${NACL_TARGET}") endif() - set(NACL_VMS_PROJECT nacl-vms-${NACL_TARGET}) + set(NACL_VMS_PROJECT nacl-vms-${nacl_target}) list(APPEND NACL_VMS_PROJECTS ${NACL_VMS_PROJECT}) add_dependencies(nacl-vms ${NACL_VMS_PROJECT}) + # TODO: Remove USE_NACL_SAIGO once the game uses YOKAI_TARGET_SYSTEM_NACL. gameSubProject( - -DCMAKE_TOOLCHAIN_FILE=${Daemon_SOURCE_DIR}/cmake/toolchain-saigo.cmake + "-DCMAKE_TOOLCHAIN_FILE=${Daemon_SOURCE_DIR}/cmake/cross-toolchain-saigo-${nacl_target}.cmake" + "-DSAIGOSDK_PREFIX=${SAIGOSDK_PREFIX}" + -DUSE_NACL_SAIGO=ON -DBUILD_GAME_NACL=ON -DBUILD_GAME_NATIVE_DLL=OFF -DBUILD_GAME_NATIVE_EXE=OFF -DUSE_NACL_SAIGO=ON - -DSAIGO_ARCH=${SAIGO_ARCH} - -DNACL_TARGET=${NACL_TARGET} ) endforeach() else() + if (NOT IS_DIRECTORY "${PNACL_SDK_PREFIX}") + message(FATAL_ERROR "PNACL_SDK_PREFIX configured as '${SAIGOSDK_PREFIX}' which is not an existing directory") + endif() + set(NACL_VMS_PROJECT nacl-vms) set(NACL_VMS_PROJECTS ${NACL_VMS_PROJECT}) @@ -240,19 +266,21 @@ function(GAMEMODULE) string(REPLACE ";" "," NACL_TARGETS_STRING "${NACL_TARGETS}") gameSubProject( - -DCMAKE_TOOLCHAIN_FILE=${Daemon_SOURCE_DIR}/cmake/toolchain-pnacl.cmake + "-DCMAKE_TOOLCHAIN_FILE=${Daemon_SOURCE_DIR}/cmake/cross-toolchain-pnacl.cmake" + "-DPNACLSDK_PREFIX=${PNACLSDK_PREFIX}" + -DUSE_NACL_SAIGO=OFF -DBUILD_GAME_NACL=ON -DBUILD_GAME_NATIVE_DLL=OFF -DBUILD_GAME_NATIVE_EXE=OFF - -DNACL_TARGETS_STRING=${NACL_TARGETS_STRING} + "-DNACL_TARGETS_STRING=${NACL_TARGETS_STRING}" ) endif() endif() set(NACL_VMS_PROJECTS ${NACL_VMS_PROJECTS} PARENT_SCOPE) - elseif (FORK EQUAL 2) # we are in the CMake sub-invocation for NaCl + elseif (GAME_BUILD_SUBINVOCATION) if (BUILD_GAME_NACL) - if (USE_NACL_SAIGO) + if (YOKAI_CXX_COMPILER_SAIGO) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) else() # Put the .nexe and .pexe files in the same directory as the engine. @@ -261,16 +289,28 @@ function(GAMEMODULE) buildGameModule("nacl") - if (USE_NACL_SAIGO) + if (YOKAI_CXX_COMPILER_SAIGO) + include(DaemonSaigoFinalize) + # Finalize NaCl executables for supported architectures. - saigo_finalize(${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/.. ${GAMEMODULE_NAME} ${NACL_TARGET}) + saigo_finalize( + "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" + "${GAMEMODULE_NAME}" + "${YOKAI_TARGET_ARCH_NAME}" + ) else() + include(DaemonPNaClFinalize) + # Revert a workaround for a bug where CMake ExternalProject lists-as-args are cut on first “;” string(REPLACE "," ";" NACL_TARGETS "${NACL_TARGETS_STRING}") # Generate NaCl executables for supported architectures. - foreach(NACL_TARGET ${NACL_TARGETS}) - pnacl_finalize(${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${GAMEMODULE_NAME} ${NACL_TARGET}) + foreach(nacl_target ${NACL_TARGETS}) + pnacl_finalize( + "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" + "${GAMEMODULE_NAME}" + "${nacl_target}" + ) endforeach() endif() endif() diff --git a/cmake/DaemonNacl.cmake b/cmake/DaemonNacl.cmake deleted file mode 100644 index e37bf06844..0000000000 --- a/cmake/DaemonNacl.cmake +++ /dev/null @@ -1,81 +0,0 @@ -# Daemon BSD Source Code -# Copyright (c) 2013-2016, Daemon Developers -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the Daemon developers nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Native client - -option(USE_NACL_SAIGO "Use Saigo toolchain to build NaCl executables" OFF) - -if (YOKAI_TARGET_SYSTEM_NACL) - # Build nexe binary. - if(USE_NACL_SAIGO) - if (NACL_TARGET STREQUAL "amd64") - add_definitions(-DNACL_BUILD_ARCH=x86) - add_definitions(-DNACL_BUILD_SUBARCH=64) - elseif (NACL_TARGET STREQUAL "i686") - add_definitions(-DNACL_BUILD_ARCH=x86) - add_definitions(-DNACL_BUILD_SUBARCH=32) - elseif (NACL_TARGET STREQUAL "armhf") - add_definitions(-DNACL_BUILD_ARCH=arm) - else() - message(FATAL_ERROR "Unsupported architecture ${NACL_TARGET}") - endif() - else() - # Those defines looks to be meaningless to produce arch-independent pexe - # with PNaCl but they must be set to anything supported by native builds. - # This requirement looks to be a PNaCl bug. - add_definitions( -DNACL_BUILD_ARCH=x86 ) - add_definitions( -DNACL_BUILD_SUBARCH=64 ) - endif() -else() - # Build native dll or native exe. - if (YOKAI_TARGET_SYSTEM_MACOS) - add_definitions( -DNACL_WINDOWS=0 -DNACL_LINUX=0 -DNACL_ANDROID=0 -DNACL_FREEBSD=0 -DNACL_OSX=1 ) - elseif (YOKAI_TARGET_SYSTEM_LINUX) - add_definitions( -DNACL_WINDOWS=0 -DNACL_LINUX=1 -DNACL_ANDROID=0 -DNACL_FREEBSD=0 -DNACL_OSX=0 ) - elseif (YOKAI_TARGET_SYSTEM_FREEBSD) - add_definitions( -DNACL_WINDOWS=0 -DNACL_LINUX=0 -DNACL_ANDROID=0 -DNACL_FREEBSD=1 -DNACL_OSX=0 ) - elseif (YOKAI_TARGET_SYSTEM_WINDOWS) - add_definitions( -DNACL_WINDOWS=1 -DNACL_LINUX=0 -DNACL_ANDROID=0 -DNACL_FREEBSD=0 -DNACL_OSX=0 ) - endif() - - if (YOKAI_TARGET_ARCH_AMD64) - add_definitions( -DNACL_BUILD_ARCH=x86 ) - add_definitions( -DNACL_BUILD_SUBARCH=64 ) - elseif (YOKAI_TARGET_ARCH_I686) - add_definitions( -DNACL_BUILD_ARCH=x86 ) - add_definitions( -DNACL_BUILD_SUBARCH=32 ) - elseif (YOKAI_TARGET_ARCH_ARMHF) - add_definitions( -DNACL_BUILD_ARCH=arm ) - else() - # NaCl does not support this architecture natively, but these defines must - # be set because nacl_config.h is included unconditionally. Use dummy x86 - # values as PNaCl does for architecture-independent builds. - add_definitions( -DNACL_BUILD_ARCH=x86 ) - add_definitions( -DNACL_BUILD_SUBARCH=64 ) - endif() -endif() - -include_directories( ${LIB_DIR}/nacl ) diff --git a/cmake/DaemonNaclHost.cmake b/cmake/DaemonNaclArchitecture.cmake similarity index 67% rename from cmake/DaemonNaclHost.cmake rename to cmake/DaemonNaclArchitecture.cmake index 7172e71d55..f23685f86f 100644 --- a/cmake/DaemonNaclHost.cmake +++ b/cmake/DaemonNaclArchitecture.cmake @@ -24,60 +24,72 @@ # (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}") + 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 "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) + message(STATUS "Available NaCl architectures: ${nacl_arch_list}") - # 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}") + list(GET nacl_arch_list 0 nacl_arch) + + message(STATUS "Primary NaCl architecture: ${nacl_arch}") add_definitions(-DDAEMON_NACL_RUNTIME_ENABLED) else() set(nacl_arch "unknown") - message(STATUS "No NaCl architecture detected") + message(STATUS "No known NaCl architecture") endif() # 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/DaemonNaclFlags.cmake b/cmake/DaemonNaclFlags.cmake new file mode 100644 index 0000000000..cbdc4b5a3f --- /dev/null +++ b/cmake/DaemonNaclFlags.cmake @@ -0,0 +1,75 @@ +# Daemon BSD Source Code +# Copyright (c) 2013-2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Native Client build configuration. + +if (YOKAI_TARGET_SYSTEM_NACL) + # Build nexe binary. + + if (YOKAI_CXX_COMPILER_SAIGO) + if (YOKAI_TARGET_ARCH_AMD64) + add_definitions(-DNACL_BUILD_ARCH=x86 -DNACL_BUILD_SUBARCH=64) + elseif (YOKAI_TARGET_ARCH_I686) + add_definitions(-DNACL_BUILD_ARCH=x86 -DNACL_BUILD_SUBARCH=32) + elseif (YOKAI_TARGET_ARCH_ARMHF) + add_definitions(-DNACL_BUILD_ARCH=arm) + else() + message(FATAL_ERROR "Unsupported architecture ${NACL_TARGET}") + endif() + else() + # Those defines looks to be meaningless to produce arch-independent pexe + # with PNaCl but they must be set to anything supported by native builds. + # This requirement looks to be a PNaCl bug. + add_definitions(-DNACL_BUILD_ARCH=x86 -DNACL_BUILD_SUBARCH=64) + endif() +else() + # Build native dll or native exe. + + if (YOKAI_TARGET_SYSTEM_MACOS) + add_definitions(-DNACL_WINDOWS=0 -DNACL_LINUX=0 -DNACL_ANDROID=0 -DNACL_FREEBSD=0 -DNACL_OSX=1) + elseif (YOKAI_TARGET_SYSTEM_LINUX) + add_definitions(-DNACL_WINDOWS=0 -DNACL_LINUX=1 -DNACL_ANDROID=0 -DNACL_FREEBSD=0 -DNACL_OSX=0) + elseif (YOKAI_TARGET_SYSTEM_FREEBSD) + add_definitions(-DNACL_WINDOWS=0 -DNACL_LINUX=0 -DNACL_ANDROID=0 -DNACL_FREEBSD=1 -DNACL_OSX=0) + elseif (YOKAI_TARGET_SYSTEM_WINDOWS) + add_definitions(-DNACL_WINDOWS=1 -DNACL_LINUX=0 -DNACL_ANDROID=0 -DNACL_FREEBSD=0 -DNACL_OSX=0) + endif() + + if (YOKAI_TARGET_ARCH_AMD64) + add_definitions(-DNACL_BUILD_ARCH=x86 -DNACL_BUILD_SUBARCH=64) + elseif (YOKAI_TARGET_ARCH_I686) + add_definitions(-DNACL_BUILD_ARCH=x86 -DNACL_BUILD_SUBARCH=32) + elseif (YOKAI_TARGET_ARCH_ARMHF) + add_definitions(-DNACL_BUILD_ARCH=arm) + else() + # NaCl does not support this architecture natively, but these defines must + # be set because nacl_config.h is included unconditionally. Use dummy x86 + # values as PNaCl does for architecture-independent builds. + add_definitions(-DNACL_BUILD_ARCH=x86 -DNACL_BUILD_SUBARCH=64) + endif() +endif() + +include_directories(${LIB_DIR}/nacl) diff --git a/cmake/DaemonPNaClFinalize.cmake b/cmake/DaemonPNaClFinalize.cmake new file mode 100644 index 0000000000..2130490030 --- /dev/null +++ b/cmake/DaemonPNaClFinalize.cmake @@ -0,0 +1,79 @@ +# Daemon BSD Source Code +# Copyright (c) 2013-2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (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(pnacl_finalize dir module arch) + include(DaemonBuildTypeGeneratorExpression) + + set(PNACL_TRANSLATE_OPTIONS + --allow-llvm-bitcode-input # FIXME: finalize as part of the build process + --pnacl-allow-exceptions + $<${RELEASE_GENEXP_COND}:-O3> + $<${DEBUG_GENEXP_COND}:-O0> + $<${RELWITHDEBINFO_GENEXP_COND}:-O2> + $<${MINSIZEREL_GENEXP_COND}:-O2> + ) + set(PEXE "${dir}/${module}${NACL_EXECUTABLE_SUFFIX}") + set(NEXE "${dir}/${module}-${arch}${NACL_TRANSLATED_EXECUTABLE_SUFFIX}") + set(STRIPPED_NEXE "${dir}/${module}-${arch}-stripped${NACL_TRANSLATED_EXECUTABLE_SUFFIX}") + + if (arch STREQUAL "i686") + set(PNACL_ARCH "i686") + elseif (arch STREQUAL "amd64") + set(PNACL_ARCH "x86-64") + elseif (arch STREQUAL "armhf") + set(PNACL_ARCH "arm") + else() + message(FATAL_ERROR "Unknown NaCl architecture ${arch}") + endif() + + add_custom_command( + OUTPUT ${NEXE} + COMMENT "Translating ${module} (${arch})" + DEPENDS ${PEXE} + COMMAND + ${PNACLPYTHON_PREFIX2} + "${PNACL_TRANSLATE}" + ${PNACL_TRANSLATE_OPTIONS} + -arch "${PNACL_ARCH}" + "${PEXE}" + -o "${NEXE}" + ) + + add_custom_command( + OUTPUT "${STRIPPED_NEXE}" + COMMENT "Stripping ${module} (${arch})" + DEPENDS "${NEXE}" + COMMAND + ${PNACLPYTHON_PREFIX2} + "${CMAKE_STRIP}" + -s + "${NEXE}" + -o "${STRIPPED_NEXE}" + ) + + add_custom_target("${module}-${arch}" ALL DEPENDS "${STRIPPED_NEXE}") + add_dependencies("${module}-${arch}" "${module}-nacl") +endfunction() diff --git a/cmake/DaemonSaigoFinalize.cmake b/cmake/DaemonSaigoFinalize.cmake new file mode 100644 index 0000000000..01f1cf1da5 --- /dev/null +++ b/cmake/DaemonSaigoFinalize.cmake @@ -0,0 +1,56 @@ +# Daemon BSD Source Code +# Copyright (c) 2023-2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (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(saigo_finalize dir module arch) + set(SUBPROJECT_NEXE "${dir}/${module}${NACL_EXECUTABLE_SUFFIX}") + set(NEXE "${dir}/../${module}-${arch}${NACL_EXECUTABLE_SUFFIX}") + set(STRIPPED_NEXE "${dir}/../${module}-${arch}-stripped${NACL_EXECUTABLE_SUFFIX}") + + add_custom_command( + OUTPUT "${NEXE}" + COMMENT "Copying ${module} (${arch})" + DEPENDS "${SUBPROJECT_NEXE}" + COMMAND + ${CMAKE_COMMAND} + -E copy + "${SUBPROJECT_NEXE}" + "${NEXE}" + ) + + add_custom_command( + OUTPUT "${STRIPPED_NEXE}" + COMMENT "Stripping ${module} (${arch})" + DEPENDS "${NEXE}" + COMMAND + "${CMAKE_STRIP}" + -s + "${NEXE}" + -o "${STRIPPED_NEXE}" + ) + + add_custom_target("${module}-${arch}" ALL DEPENDS "${STRIPPED_NEXE}") + add_dependencies("${module}-${arch}" "${module}-nacl") +endfunction() diff --git a/cmake/cross-toolchain-pnacl.cmake b/cmake/cross-toolchain-pnacl.cmake new file mode 100644 index 0000000000..eb71dbc5cc --- /dev/null +++ b/cmake/cross-toolchain-pnacl.cmake @@ -0,0 +1,106 @@ +# Daemon BSD Source Code +# Copyright (c) 2013-2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# We can't use CMAKE_EXECUTABLE_SUFFIX because the Generic Platform will reset it +# and creating a Platform module for setting CMAKE_EXECUTABLE_SUFFIX is overkill. +set(NACL_EXECUTABLE_SUFFIX ".pexe") +set(NACL_TRANSLATED_EXECUTABLE_SUFFIX ".nexe") + +if (CMAKE_HOST_WIN32) + set(PNACL_EXECUTABLE_SUFFIX ".bat") +else() + set(PNACL_EXECUTABLE_SUFFIX "") +endif() + +set(PNACL_TRIPLET "pnacl") + +if ("${PNACLSDK_PREFIX}" STREQUAL "") + find_program(PATH_PNACL_CLANG NAMES "${PNACL_TRIPLET}-clang${PNACL_EXECUTABLE_SUFFIX}") + get_filename_component(PNACLSDK_PREFIX ${PATH_PNACL_CLANG} DIRECTORY) +endif() + +list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES PNACLSDK_PREFIX) + +set(CMAKE_SYSTEM_NAME "Generic") + +set(CMAKE_C_COMPILER "${PNACLSDK_PREFIX}/bin/${PNACL_TRIPLET}-clang${PNACL_EXECUTABLE_SUFFIX}") +set(CMAKE_CXX_COMPILER "${PNACLSDK_PREFIX}/bin/${PNACL_TRIPLET}-clang++${PNACL_EXECUTABLE_SUFFIX}") +set(CMAKE_AR "${PNACLSDK_PREFIX}/bin/${PNACL_TRIPLET}-ar${PNACL_EXECUTABLE_SUFFIX}" CACHE FILEPATH "Archiver" FORCE) +set(CMAKE_RANLIB "${PNACLSDK_PREFIX}/bin/${PNACL_TRIPLET}-ranlib${PNACL_EXECUTABLE_SUFFIX}") +set(PNACL_TRANSLATE "${PNACLSDK_PREFIX}/bin/${PNACL_TRIPLET}-translate${PNACL_EXECUTABLE_SUFFIX}") +set(CMAKE_STRIP "${PNACLSDK_PREFIX}/bin/${PNACL_TRIPLET}-strip${PNACL_EXECUTABLE_SUFFIX}") +set(CMAKE_FIND_ROOT_PATH "${PNACLSDK_PREFIX}/le32-nacl") + +set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1) +set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1) +set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) +set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1) +set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1) +set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1) +set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@") +set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") + +set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") +set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") +set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -DNDEBUG") +set(CMAKE_C_FLAGS_DEBUG_INIT "-g") + +set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "${CMAKE_C_FLAGS_MINSIZEREL_INIT}") +set(CMAKE_CXX_FLAGS_RELEASE_INIT "${CMAKE_C_FLAGS_RELEASE_INIT}") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${CMAKE_C_FLAGS_RELWITHDEBINFO_INIT}") +set(CMAKE_CXX_FLAGS_DEBUG_INIT "${CMAKE_C_FLAGS_DEBUG_INIT}") + +if (NOT CMAKE_HOST_WIN32) + find_package(Python) + + if (Python_Interpreter_FOUND) + set(PNACLPYTHON_PREFIX "env PNACLPYTHON=${Python_EXECUTABLE} ") + set(PNACLPYTHON_PREFIX2 env "PNACLPYTHON=${Python_EXECUTABLE} ") + message(STATUS "Using PNACL Python executable: ${Python_EXECUTABLE}") + else() + message(FATAL_ERROR "Please install python (and run in a python virtualenv if that's not enough).") + endif() +endif() + +# These commands can fail on windows if there is a space at the beginning +set(CMAKE_C_CREATE_STATIC_LIBRARY "${PNACLPYTHON_PREFIX} rc ") +set(CMAKE_CXX_CREATE_STATIC_LIBRARY "${PNACLPYTHON_PREFIX} rc ") + +set(CMAKE_C_COMPILE_OBJECT "${PNACLPYTHON_PREFIX} -o -c ") +set(CMAKE_CXX_COMPILE_OBJECT "${PNACLPYTHON_PREFIX} -o -c ") + +set(CMAKE_C_LINK_EXECUTABLE "${PNACLPYTHON_PREFIX} -o ") +set(CMAKE_CXX_LINK_EXECUTABLE "${PNACLPYTHON_PREFIX} -o ") + +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + +set(NACL ON) + +set(CMAKE_C_FLAGS "") +set(CMAKE_CXX_FLAGS "") diff --git a/cmake/cross-toolchain-saigo-amd64.cmake b/cmake/cross-toolchain-saigo-amd64.cmake new file mode 100644 index 0000000000..c755d9b2b1 --- /dev/null +++ b/cmake/cross-toolchain-saigo-amd64.cmake @@ -0,0 +1,28 @@ +# Daemon BSD Source Code +# Copyright (c) 2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set(SAIGO_ARCH "x86_64") +include("${CMAKE_CURRENT_LIST_DIR}/cross-toolchain-saigo-common.cmake") diff --git a/cmake/cross-toolchain-saigo-armhf.cmake b/cmake/cross-toolchain-saigo-armhf.cmake new file mode 100644 index 0000000000..7197c47049 --- /dev/null +++ b/cmake/cross-toolchain-saigo-armhf.cmake @@ -0,0 +1,28 @@ +# Daemon BSD Source Code +# Copyright (c) 2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set(SAIGO_ARCH "arm") +include("${CMAKE_CURRENT_LIST_DIR}/cross-toolchain-saigo-common.cmake") diff --git a/cmake/cross-toolchain-saigo-common.cmake b/cmake/cross-toolchain-saigo-common.cmake new file mode 100644 index 0000000000..0c7a928e40 --- /dev/null +++ b/cmake/cross-toolchain-saigo-common.cmake @@ -0,0 +1,79 @@ +# Daemon BSD Source Code +# Copyright (c) 2023-2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# We can't use CMAKE_EXECUTABLE_SUFFIX because the Generic Platform will reset it +# and creating a Platform module for setting CMAKE_EXECUTABLE_SUFFIX is overkill. +set(NACL_EXECUTABLE_SUFFIX ".nexe") + +set(SAIGO_TRIPLET "${SAIGO_ARCH}-nacl") + +if ("${SAIGOSDK_PREFIX}" STREQUAL "") + find_program(PATH_SAIGO_CLANG NAMES "${SAIGO_TRIPLET}-clang") + get_filename_component(SAIGOSDK_PREFIX ${PATH_SAIGO_CLANG} DIRECTORY) +endif() + +list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES SAIGOSDK_PREFIX) + +set(CMAKE_SYSTEM_NAME "Generic") + +set(CMAKE_C_COMPILER "${SAIGOSDK_PREFIX}/bin/${SAIGO_TRIPLET}-clang") +set(CMAKE_CXX_COMPILER "${SAIGOSDK_PREFIX}/bin/${SAIGO_TRIPLET}-clang++") +set(CMAKE_AR "${SAIGOSDK_PREFIX}/bin/${SAIGO_TRIPLET}-ar" CACHE FILEPATH "Archiver" FORCE) +set(CMAKE_RANLIB "${SAIGOSDK_PREFIX}/bin/${SAIGO_TRIPLET}-ranlib") +set(CMAKE_STRIP "${SAIGOSDK_PREFIX}/bin/${SAIGO_TRIPLET}-strip") +set(CMAKE_FIND_ROOT_PATH "${SAIGOSDK_PREFIX}/${SAIGO_TRIPLET}") + +# Copy-pasted from the PNaCl toolchain, it's not sure we need it. +set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1) +set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1) +set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) +set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1) +set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1) +set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1) +set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@") +set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") + +# Copy-pasted from the PNaCl toolchain, it's not sure we need it. +# These commands can fail on windows if there is a space at the beginning +set(CMAKE_C_CREATE_STATIC_LIBRARY " rc ") +set(CMAKE_CXX_CREATE_STATIC_LIBRARY " rc ") + +set(CMAKE_C_COMPILE_OBJECT " -o -c ") +set(CMAKE_CXX_COMPILE_OBJECT " -o -c ") + +set(CMAKE_C_LINK_EXECUTABLE " -o ") +set(CMAKE_CXX_LINK_EXECUTABLE " -o ") + +# Copy-pasted from the PNaCl toolchain, it's not sure we need it. +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + +set(NACL ON) + +set(CMAKE_C_FLAGS "") +set(CMAKE_CXX_FLAGS "") diff --git a/cmake/cross-toolchain-saigo-i686.cmake b/cmake/cross-toolchain-saigo-i686.cmake new file mode 100644 index 0000000000..1bd9b1f0c5 --- /dev/null +++ b/cmake/cross-toolchain-saigo-i686.cmake @@ -0,0 +1,39 @@ +# Daemon BSD Source Code +# Copyright (c) 2026, Daemon Developers +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the Daemon developers nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set(SAIGO_ARCH "i686") +include("${CMAKE_CURRENT_LIST_DIR}/cross-toolchain-saigo-common.cmake") + +if (EXISTS "${SAIGOSDK_PREFIX}/x86_64-nacl/lib32") + # This will search libraries in paths in this order: + # - i686-nacl/lib + # - x86_64-nacl/lib32 + # - x86_64-nacl/lib + # The last path is wrong but is not used when the lib is found before, + # so it is meant to work on well-formed SDK installations. + list(APPEND CMAKE_FIND_ROOT_PATH "${SAIGOSDK_PREFIX}/x86_64-nacl") + set(CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX "32") +endif() diff --git a/cmake/toolchain-pnacl.cmake b/cmake/toolchain-pnacl.cmake deleted file mode 100644 index b19f61e8ec..0000000000 --- a/cmake/toolchain-pnacl.cmake +++ /dev/null @@ -1,151 +0,0 @@ -# Daemon BSD Source Code -# Copyright (c) 2013-2016, Daemon Developers -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the Daemon developers nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set(PLATFORM_PREFIX ${DEPS_DIR}/pnacl/bin) -set(PLATFORM_TRIPLET "pnacl") - -if (WIN32) - set(PNACL_BIN_EXT ".bat") -else() - set(PNACL_BIN_EXT "") -endif() - -set(PLATFORM_EXE_SUFFIX ".pexe") - -set(CMAKE_SYSTEM_NAME "Generic") - -set(CMAKE_C_COMPILER "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-clang${PNACL_BIN_EXT}") -set(CMAKE_CXX_COMPILER "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-clang++${PNACL_BIN_EXT}") -set(CMAKE_AR "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-ar${PNACL_BIN_EXT}" CACHE FILEPATH "Archiver" FORCE) -set(CMAKE_RANLIB "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-ranlib${PNACL_BIN_EXT}") -set(PNACL_TRANSLATE "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-translate${PNACL_BIN_EXT}") -set(PNACL_STRIP "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-strip${PNACL_BIN_EXT}") -set(CMAKE_FIND_ROOT_PATH "${PLATFORM_PREFIX}/../le32-nacl") - -set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1) -set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1) -set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1) -set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@") -set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") - -set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG") -set(CMAKE_C_FLAGS_RELEASE_INIT "-O3 -DNDEBUG") -set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -DNDEBUG") -set(CMAKE_C_FLAGS_DEBUG_INIT "-g") - -set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "${CMAKE_C_FLAGS_MINSIZEREL_INIT}") -set(CMAKE_CXX_FLAGS_RELEASE_INIT "${CMAKE_C_FLAGS_RELEASE_INIT}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "${CMAKE_C_FLAGS_RELWITHDEBINFO_INIT}") -set(CMAKE_CXX_FLAGS_DEBUG_INIT "${CMAKE_C_FLAGS_DEBUG_INIT}") - -if (NOT CMAKE_HOST_WIN32) - find_package(Python) - - if (Python_Interpreter_FOUND) - set(PNACLPYTHON_PREFIX "env PNACLPYTHON=${Python_EXECUTABLE} ") - set(PNACLPYTHON_PREFIX2 env "PNACLPYTHON=${Python_EXECUTABLE} ") - message(STATUS "Using PNACL Python executable: ${Python_EXECUTABLE}") - else() - message(FATAL_ERROR "Please install python (and run in a python virtualenv if that's not enough).") - endif() -endif() - -# These commands can fail on windows if there is a space at the beginning -set(CMAKE_C_CREATE_STATIC_LIBRARY "${PNACLPYTHON_PREFIX} rc ") -set(CMAKE_CXX_CREATE_STATIC_LIBRARY "${PNACLPYTHON_PREFIX} rc ") - -set(CMAKE_C_COMPILE_OBJECT "${PNACLPYTHON_PREFIX} -o -c ") -set(CMAKE_CXX_COMPILE_OBJECT "${PNACLPYTHON_PREFIX} -o -c ") - -set(CMAKE_C_LINK_EXECUTABLE "${PNACLPYTHON_PREFIX} -o ") -set(CMAKE_CXX_LINK_EXECUTABLE "${PNACLPYTHON_PREFIX} -o ") - -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) - -set(NACL ON) - -set(CMAKE_C_FLAGS "") -set(CMAKE_CXX_FLAGS "") - -function(pnacl_finalize dir module arch) - include(DaemonBuildTypeGeneratorExpression) - - set(PNACL_TRANSLATE_OPTIONS - --allow-llvm-bitcode-input # FIXME: finalize as part of the build process - --pnacl-allow-exceptions - $<${RELEASE_GENEXP_COND}:-O3> - $<${DEBUG_GENEXP_COND}:-O0> - $<${RELWITHDEBINFO_GENEXP_COND}:-O2> - $<${MINSIZEREL_GENEXP_COND}:-O2> - ) - set(PEXE ${dir}/${module}.pexe) - set(NEXE ${dir}/${module}-${arch}.nexe) - set(STRIPPED_NEXE ${dir}/${module}-${arch}-stripped.nexe) - - if (arch STREQUAL "i686") - set(PNACL_ARCH "i686") - elseif (arch STREQUAL "amd64") - set(PNACL_ARCH "x86-64") - elseif (arch STREQUAL "armhf") - set(PNACL_ARCH "arm") - else() - message(FATAL_ERROR "Unknown NaCl architecture ${arch}") - endif() - - add_custom_command( - OUTPUT ${NEXE} - COMMENT "Translating ${module} (${arch})" - DEPENDS ${PEXE} - COMMAND - ${PNACLPYTHON_PREFIX2} - "${PNACL_TRANSLATE}" - ${PNACL_TRANSLATE_OPTIONS} - -arch ${PNACL_ARCH} - ${PEXE} - -o ${NEXE} - ) - - add_custom_command( - OUTPUT ${STRIPPED_NEXE} - COMMENT "Stripping ${module} (${arch})" - DEPENDS ${NEXE} - COMMAND - ${PNACLPYTHON_PREFIX2} - "${PNACL_STRIP}" - -s - ${NEXE} - -o ${STRIPPED_NEXE} - ) - - add_custom_target(${module}-${arch} ALL DEPENDS ${STRIPPED_NEXE}) - add_dependencies(${module}-${arch} ${module}-nacl) -endfunction() diff --git a/cmake/toolchain-saigo.cmake b/cmake/toolchain-saigo.cmake deleted file mode 100644 index 75374527b3..0000000000 --- a/cmake/toolchain-saigo.cmake +++ /dev/null @@ -1,75 +0,0 @@ -set(PLATFORM_PREFIX "${DEPS_DIR}/saigo_newlib/bin") -set(PLATFORM_TRIPLET "${SAIGO_ARCH}-nacl") -set(PLATFORM_EXE_SUFFIX ".nexe") - -set(CMAKE_SYSTEM_NAME "Generic") - -set(CMAKE_C_COMPILER "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-clang") -set(CMAKE_CXX_COMPILER "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-clang++") -set(CMAKE_AR "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-ar" CACHE FILEPATH "Archiver" FORCE) -set(CMAKE_RANLIB "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-ranlib") -set(SAIGO_STRIP "${PLATFORM_PREFIX}/${PLATFORM_TRIPLET}-strip") -set(CMAKE_FIND_ROOT_PATH "${PLATFORM_PREFIX}/../${PLATFORM_TRIPLET}") - -# Copy-pasted from the PNaCl toolchain, it's not sure we need it. -set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1) -set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1) -set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1) -set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@") -set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") - -# Copy-pasted from the PNaCl toolchain, it's not sure we need it. -# These commands can fail on windows if there is a space at the beginning -set(CMAKE_C_CREATE_STATIC_LIBRARY " rc ") -set(CMAKE_CXX_CREATE_STATIC_LIBRARY " rc ") - -set(CMAKE_C_COMPILE_OBJECT " -o -c ") -set(CMAKE_CXX_COMPILE_OBJECT " -o -c ") - -set(CMAKE_C_LINK_EXECUTABLE " -o ") -set(CMAKE_CXX_LINK_EXECUTABLE " -o ") - -# Copy-pasted from the PNaCl toolchain, it's not sure we need it. -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) - -set(NACL ON) - -set(CMAKE_C_FLAGS "") -set(CMAKE_CXX_FLAGS "") - -function(saigo_finalize dir module arch) - set(SUBPROJECT_NEXE ${dir}/nacl-vms-${arch}/${module}.nexe) - set(NEXE ${dir}/${module}-${arch}.nexe) - set(STRIPPED_NEXE ${dir}/${module}-${arch}-stripped.nexe) - - add_custom_command( - OUTPUT ${NEXE} - COMMENT "Copying ${module} (${arch})" - DEPENDS ${SUBPROJECT_NEXE} - COMMAND - ${CMAKE_COMMAND} - -E copy - ${SUBPROJECT_NEXE} - ${NEXE} - ) - - add_custom_command( - OUTPUT ${STRIPPED_NEXE} - COMMENT "Stripping ${module} (${arch})" - DEPENDS ${NEXE} - COMMAND - "${SAIGO_STRIP}" - -s - ${NEXE} - -o ${STRIPPED_NEXE} - ) - - add_custom_target(${module}-${arch} ALL DEPENDS ${STRIPPED_NEXE}) - add_dependencies(${module}-${arch} ${module}-nacl) -endfunction() diff --git a/external_deps/sdk-build.sh b/external_deps/sdk-build.sh new file mode 100755 index 0000000000..e90e0ace1f --- /dev/null +++ b/external_deps/sdk-build.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +# Exit on undefined variable and error. +set -u -e -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +WORK_DIR="${PWD}" +DOWNLOAD_DIR="${WORK_DIR}/download_cache" + +# This should match the SAIGOSDK_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. +SAIGOSDK_VERSION=20261013 +# Can be a tag like v${SAIGOSDK_VERSION}, or a full commit hash +SAIGOSDK_REF="v${SAIGOSDK_VERSION}" + +REPO_BASENAME=saigo-nacl-sdk +REPO_URL="https://github.com/DaemonEngine/${REPO_BASENAME}" +ARCHIVE_PATH="${DOWNLOAD_DIR}/saigosdk-${SAIGOSDK_REF}.tar.gz" + +usage() { + echo "Usage: $0 - (build | install | package | wipe)..." + echo "- should normally be your current native platform." + echo "For a list of supported platforms see ${REPO_URL}/tree/master/tools/release/conf" + echo "Actions:" + echo " build - build all tools and libraries in the SDK" + echo " install - install final build products to ${WORK_DIR}/saigosdk--_${SAIGOSDK_VERSION}/" + echo " wipe - delete build products (except download cache) AND install directory" + echo "If you want to build only a subset of packages, prefer using the" + echo "${REPO_URL} CMake build directly." + echo "Some global configuration options are available via environment" + echo "variables; see ${REPO_URL}/tree/master/tools/release/build" +} + +download() { + test -f "${ARCHIVE_PATH}" && return + mkdir -p "${DOWNLOAD_DIR}" + curl --fail -L "${DOWNLOAD_URL}" -o "${ARCHIVE_PATH}" +} + +if [ "$#" -lt 2 ] +then + usage + exit 1 +fi + +PLATFORM="$1" +shift + +if grep -q -E '^[0-9a-f]{40}$' <<< "${SAIGOSDK_REF}" +then + DOWNLOAD_URL="https://github.com/DaemonEngine/saigo-nacl-sdk/archive/${SAIGOSDK_REF}.tar.gz" + TARBALL_OUTER_DIR="${REPO_BASENAME}-${SAIGOSDK_REF}" +elif grep -q -E '^v[0-9]' <<< "${SAIGOSDK_REF}" +then + # The 'v' from the tag name is mysteriously removed??? + TARBALL_OUTER_DIR="${REPO_BASENAME}-${SAIGOSDK_REF:1}" + DOWNLOAD_URL="https://github.com/DaemonEngine/saigo-nacl-sdk/archive/refs/tags/${SAIGOSDK_REF}.tar.gz" +fi + +INSTALL_DIR="${WORK_DIR}/saigosdk-${PLATFORM}_${SAIGOSDK_VERSION}" +BUILD_DIR="${WORK_DIR}/build-saigosdk_${SAIGOSDK_VERSION}" +REPO_DIR="${BUILD_DIR}/${TARBALL_OUTER_DIR}" + +for target in "$@" +do + case "${target}" in + build) + download + mkdir -p "${BUILD_DIR}" + tar xzf "${ARCHIVE_PATH}" -C "${BUILD_DIR}" + ( + cd "${REPO_DIR}" + tools/release/build "${PLATFORM}" + ) + ;; + install) + cp -R "${REPO_DIR}/build/${PLATFORM}/install/." "${INSTALL_DIR}/" + ;; + wipe) + rm -rf "${BUILD_DIR}" "${INSTALL_DIR}" + ;; + *) + usage + exit 1 + ;; + esac +done diff --git a/src/engine/framework/VirtualMachine.cpp b/src/engine/framework/VirtualMachine.cpp index df2739b9f3..ee0a47e053 100644 --- a/src/engine/framework/VirtualMachine.cpp +++ b/src/engine/framework/VirtualMachine.cpp @@ -75,27 +75,60 @@ 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_RUNTIME_ENABLED) +// Many BSDs have a Linuxulator, for now we only tested one. +#if defined(__linux__) || defined(__FreeBSD__) +#define DAEMON_NACL_RUNTIME_LINUX +#if YOKAI_ARCH_I686 || YOKAI_ARCH_ARM64 || YOKAI_ARCH_ARMHF +#define DAEMON_NACL_BOOSTRAP_ENABLED +#endif // !(YOKAI_ARCH_I686 || YOKAI_ARCH_ARM64 || YOKAI_ARCH_ARMHF) +#endif // defined(__linux__) || defined(DAEMON_LINUXULATOR) +#endif // defined(DAEMON_NACL_RUNTIME_ENABLED) + +#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); -static Cvar::Cvar workaround_box64_disableBootstrap( - "workaround.box64.disableBootstrap", - "Disable NaCl bootstrap helper when using Box64 emulation", - Cvar::NONE, true); - 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)) { + const std::string libs_linux_amd64 = "libs-linux-amd64"; + const std::string libgcc_linux_amd64 = "libgcc_s.so.1"; + + std::string libsDirPath = FS::Path::Build(naclPath, libs_linux_amd64); + std::string libGccPath = FS::Path::Build(libsDirPath, libgcc_linux_amd64); + + if (FS::RawPath::FileExists(libGccPath)) { + Sys::SetEnv("BOX64_LD_LIBRARY_PATH", libsDirPath.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 +154,31 @@ static std::string ResolveBox64Path() { "Install Box64 or set vm.box64.path to the full path of the box64 binary."); return ""; // unreachable } -#endif +#endif // DAEMON_NACL_BOX64_EMULATION +#endif // DAEMON_NACL_RUNTIME_ENABLED -static Cvar::Cvar vm_nacl_qualification( - "vm.nacl.qualification", - "Enable NaCl loader platform qualification", - Cvar::INIT, true); +#if defined(DAEMON_NACL_RUNTIME_ENABLED) +static constexpr bool vmAvailable = true; +#else // !defined(DAEMON_NACL_RUNTIME_ENABLED) +static constexpr bool vmAvailable = false; +#endif // !defined(DAEMON_NACL_RUNTIME_ENABLED) -static Cvar::Cvar vm_nacl_bootstrap( - "vm.nacl.bootstrap", - "Use NaCl bootstrap helper", - Cvar::INIT, true); +static Cvar::Cvar vm_nacl_available( + "vm.nacl.available", + "Whether NaCl runtime is available on this platform", + Cvar::ROM, vmAvailable); +#if defined(DAEMON_NACL_RUNTIME_ENABLED) static Cvar::Cvar vm_timeout( "vm.timeout", "Receive timeout in seconds", Cvar::NONE, 2); -#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 -static Cvar::Cvar vm_nacl_available( - "vm.nacl.available", - "Whether NaCl runtime is available on this platform", - Cvar::ROM, false); -#endif +static Cvar::Cvar vm_nacl_qualification( + "vm.nacl.qualification", + "Enable NaCl loader platform qualification", + Cvar::INIT, true); +#endif // defined(DAEMON_NACL_RUNTIME_ENABLED) namespace VM { @@ -177,6 +207,22 @@ static void CheckMinAddressSysctlTooLarge() #endif // __linux__ } +#if defined(DAEMON_NACL_RUNTIME_LINUX) && (defined(YOKAI_ARCH_ARM64) || defined(YOKAI_ARCH_ARMHF)) +static bool OnArm64() +{ +#if defined(YOKAI_ARCH_ARM64) + return true; +#elif defined(YOKAI_ARCH_ARMHF) + struct utsname buf; + if (!uname(&buf)) { + return !strcmp(buf.machine, "aarch64"); + } + + return false; +#endif // defined(YOKAI_ARCH_ARMHF) +} +#endif + // Platform-specific code to load a module static std::pair InternalLoadModule(std::pair pair, const char* const* args, bool reserve_mem, FS::File stderrRedirect = FS::File(), bool inheritEnvironment = false) { @@ -242,8 +288,12 @@ static std::pair InternalLoadModule(std::pair InternalLoadModule(std::pair InternalLoadModule(std::pair("LD_LIBRARY_PATH=lib-armhf"); + + if (0 != posix_spawn_file_actions_addchdir_np(&fileActions, FS::GetLibPath().c_str())) { + Sys::Error("failed posix_spawn_file_actions_addchdir"); + } + } +#endif // By default, the child process gets an empty environment for sandboxing. // When Box64 emulation is used, the child needs to inherit the parent's // environment so Box64 can find its configuration (e.g. ~/.box64rc, HOME) // and honor settings like BOX64_DYNAREC_PERFMAP. - char* emptyEnv[] = {nullptr}; char** envp = inheritEnvironment ? environ : emptyEnv; int err = posix_spawn(&pid, args[0], &fileActions, nullptr, const_cast(args), envp); posix_spawn_file_actions_destroy(&fileActions); @@ -300,57 +358,205 @@ static std::pair InternalLoadModule(std::pair(probe.data()), + nullptr, + }; + + execve(probe.data(), argv, environ); + + switch (errno) + { + case ENOEXEC: + // The 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 ExeSupport::Unknown; + } + + if (!WIFEXITED(status)) { + return ExeSupport::Unknown; + } + + switch (WEXITSTATUS(status)) + { + case 100: + return ExeSupport::Unsupported; + + case 101: + case 102: + return ExeSupport::Unknown; + + default: + // The probe has been executed properly. + return ExeSupport::Supported; + } +} +#endif // defined(DAEMON_NACL_RUNTIME_LINUX) && defined(NACL_ARCH_ARM64) + +#if defined(DAEMON_NACL_RUNTIME_ENABLED) 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 - const char* naclPath = DAEMON_NACL_RUNTIME_PATH_STRING; -#else - const std::string& naclPath = libPath; -#endif std::vector args; char rootSocketRedir[32]; - std::string module, nacl_loader, irt, bootstrap, modulePath, verbosity; FS::File stderrRedirect; -#if defined(DAEMON_NACL_BOX64_EMULATION) - std::string box64Path; - bool usingBox64 = false; -#endif + bool inheritEnvironment = false; + +#if defined(DAEMON_NACL_RUNTIME_PATH) + const char* naclPath = DAEMON_NACL_RUNTIME_PATH_STRING; +#else // !defined(DAEMON_NACL_RUNTIME_PATH) + const std::string& naclPath = libPath; +#endif // !defined(DAEMON_NACL_RUNTIME_PATH) + #if !defined(_WIN32) || defined(_WIN64) - constexpr bool win32Force64Bit = false; -#else + 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(DAEMON_NACL_RUNTIME_LINUX) && defined(YOKAI_ARCH_ARM64) + constexpr bool hasMultiarch = true; +#else + constexpr bool hasMultiarch = false; #endif + std::string bootstrapPath; + +#if defined(DAEMON_NACL_BOOSTRAP_ENABLED) + bool hasBootstrap = true; +#else // !defined(DAEMON_NACL_BOOSTRAP_ENABLED) + constexpr bool hasBootstrap = false; + Q_UNUSED(bootstrapPath); +#endif // !defined(DAEMON_NACL_BOOSTRAP_ENABLED) + + std::string box64Path; + +#if defined(DAEMON_NACL_BOX64_EMULATION) + constexpr bool hasBox64 = true; +#else // !defined(DAEMON_NACL_BOX64_EMULATION) + constexpr bool hasBox64 = false; + Q_UNUSED(box64Path); +#endif // !defined(DAEMON_NACL_BOX64_EMULATION) + +#if defined(DAEMON_NACL_RUNTIME_LINUX) && defined(YOKAI_ARCH_ARM64) + /* We later turn this boolean off when we detect armhf support is not + provided on arm64. */ + bool hasArmhf = true; +#endif // !defined(YOKAI_ARCH_ARMHF) + + bool useMultiarch = hasMultiarch; + bool useBox64 = hasBox64; + +#if defined(DAEMON_NACL_RUNTIME_LINUX) && defined(YOKAI_ARCH_ARM64) + const std::string libs_linux_armhf = "libs-linux-armhf"; + const std::string libld_linux_armhf = "ld-linux-armhf.so.3"; + + std::string libsDirPath = FS::Path::Build(libPath, libs_linux_armhf); + std::string libLoaderPath = FS::Path::Build(libsDirPath, libld_linux_armhf); + + switch (CheckExeSupport(libLoaderPath)) + { + case ExeSupport::Supported: + Log::Notice("Working multiarch support."); + break; + + case ExeSupport::Unsupported: + Log::Notice("Unsupported multiarch."); + hasArmhf = false; + break; + + case ExeSupport::Unknown: + Log::Warn("Cannot determine multiarch support."); + hasArmhf = false; + break; + } + + if (!hasArmhf) { + useMultiarch = false; + } +#endif // defined(DAEMON_NACL_RUNTIME_LINUX) && defined(YOKAI_ARCH_ARM64) + + if (useMultiarch && useBox64) { + Log::Notice("Preferring multiarch over Box64 emulation."); + useBox64 = false; + } + + bool useBootstrap = hasBootstrap && !useBox64; + + std::string arch = (useBox64 || i686ForceAmd64) ? "amd64" : DAEMON_NACL_ARCH_STRING; + + std::string moduleName = Str::Format("%s-%s.nexe", name, arch); + std::string irt = FS::Path::Build(naclPath, Str::Format("irt_core-%s.nexe", arch)); + std::string nacl_loader = FS::Path::Build(naclPath, Str::Format("nacl_loader-%s%s", arch, EXE_EXT)); + + std::string modulePath; + // 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); - if (const FS::LoadedPakInfo* pak = FS::PakPath::LocateFile(module)) - Log::Notice("Extracting VM module %s from %s...", module.c_str(), pak->path.c_str()); - FS::PakPath::CopyFile(module, out); + FS::File out = FS::HomePath::OpenWrite(moduleName); + if (const FS::LoadedPakInfo* pak = FS::PakPath::LocateFile(moduleName)) + Log::Notice("Extracting VM module %s from %s...", moduleName.c_str(), pak->path.c_str()); + FS::PakPath::CopyFile(moduleName, out); out.Close(); } catch (std::system_error& err) { - Sys::Drop("VM: Failed to extract VM module %s: %s", module, err.what()); + Sys::Drop("VM: Failed to extract VM module %s: %s", moduleName, err.what()); } - modulePath = FS::Path::Build(FS::GetHomePath(), module); + modulePath = FS::Path::Build(FS::GetHomePath(), moduleName); } else { - modulePath = FS::Path::Build(libPath, module); + modulePath = FS::Path::Build(libPath, moduleName); } // Generate command line Q_snprintf(rootSocketRedir, sizeof(rootSocketRedir), "%d:%d", ROOT_SOCKET_FD, (int)(intptr_t)pair.second.GetHandle()); - irt = FS::Path::Build(naclPath, win32Force64Bit - ? "irt_core-amd64.nexe" - : Str::Format("irt_core-%s.nexe", DAEMON_NACL_ARCH_STRING)); - nacl_loader = FS::Path::Build(naclPath, win32Force64Bit ? "nacl_loader-amd64" EXE_EXT : "nacl_loader" EXE_EXT); if (!FS::RawPath::FileExists(modulePath)) { Sys::Error("VM module file not found: %s", modulePath); @@ -364,99 +570,89 @@ static 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 +662,10 @@ static std::pair CreateNaClVM(std::pair CreateNaClVM(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 +801,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-armhf/nacl_helper_bootstrap-armhf.cpp deleted file mode 100644 index ec16447482..0000000000 --- a/tools/nacl_helper_bootstrap-armhf/nacl_helper_bootstrap-armhf.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* -=========================================================================== -Daemon BSD Source Code -Copyright (c) 2022, Daemon Developers -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Daemon developers nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -=========================================================================== -*/ - -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) { - char *directory = dirname(strdup(argv[0])); - - int err = chdir(directory); - - if (err != 0) { - return err; - } - - err = putenv(strdup("LD_LIBRARY_PATH=lib-armhf")); - - if (err != 0) { - return err; - } - - char *helper = strdup("./nacl_helper_bootstrap"); - 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)); - - return 1; -}