From 1931c18d3a5b2c7974dbf0c370b9ed87247bd4f3 Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Thu, 12 Nov 2026 23:59:53 -0500 Subject: [PATCH 1/4] fix(xbox): keep nxdk compatibility in Moonlight --- .gitmodules | 4 +- README.md | 33 +++--- cmake/modules/GetOpenSSL.cmake | 5 +- cmake/moonlight-dependencies.cmake | 35 +++---- cmake/nxdk-compat.cmake | 86 ++++++++++++++++ cmake/nxdk.cmake | 7 ++ cmake/xbox-build.cmake | 6 +- scripts/ffmpeg-nxdk-cc.sh | 5 +- scripts/ffmpeg-nxdk-cxx.sh | 3 + src/_nxdk_compat/ffmpeg_compat.h | 112 +++++++++++++++++++++ src/_nxdk_compat/include/dirent.h | 49 +++++++++ src/_nxdk_compat/include/fcntl.h | 25 +++++ src/_nxdk_compat/include/memory.h | 6 ++ src/_nxdk_compat/include/moonlight_posix.h | 33 ++++++ src/_nxdk_compat/include/netinet/in.h | 6 ++ src/_nxdk_compat/include/netinet/tcp.h | 6 ++ src/_nxdk_compat/include/poll.h | 6 ++ src/_nxdk_compat/include/sys/ioctl.h | 6 ++ src/_nxdk_compat/include/sys/select.h | 6 ++ src/_nxdk_compat/include/sys/stat.h | 57 +++++++++++ src/_nxdk_compat/include/sys/time.h | 25 +++++ src/_nxdk_compat/include/sys/types.h | 12 +++ src/_nxdk_compat/include/unistd.h | 6 ++ src/_nxdk_compat/network/lwipopts.h.in | 31 ++++++ src/_nxdk_compat/runtime.c | 58 +++++++++++ third-party/nxdk | 2 +- 26 files changed, 586 insertions(+), 44 deletions(-) create mode 100644 cmake/nxdk-compat.cmake create mode 100644 src/_nxdk_compat/ffmpeg_compat.h create mode 100644 src/_nxdk_compat/include/dirent.h create mode 100644 src/_nxdk_compat/include/fcntl.h create mode 100644 src/_nxdk_compat/include/memory.h create mode 100644 src/_nxdk_compat/include/moonlight_posix.h create mode 100644 src/_nxdk_compat/include/netinet/in.h create mode 100644 src/_nxdk_compat/include/netinet/tcp.h create mode 100644 src/_nxdk_compat/include/poll.h create mode 100644 src/_nxdk_compat/include/sys/ioctl.h create mode 100644 src/_nxdk_compat/include/sys/select.h create mode 100644 src/_nxdk_compat/include/sys/stat.h create mode 100644 src/_nxdk_compat/include/sys/time.h create mode 100644 src/_nxdk_compat/include/sys/types.h create mode 100644 src/_nxdk_compat/include/unistd.h create mode 100644 src/_nxdk_compat/network/lwipopts.h.in create mode 100644 src/_nxdk_compat/runtime.c diff --git a/.gitmodules b/.gitmodules index 209a113..99e9d36 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,8 +19,8 @@ shallow = true [submodule "third-party/nxdk"] path = third-party/nxdk - url = https://github.com/ReenigneArcher/nxdk.git - branch = codex/moonlight-runtime + url = https://github.com/XboxDev/nxdk.git + branch = master shallow = true [submodule "third-party/openssl"] path = third-party/openssl diff --git a/README.md b/README.md index 9f49b5e..f261144 100644 --- a/README.md +++ b/README.md @@ -176,22 +176,23 @@ Coverage should come from this host-native test build instead of the cross-compi ### Dependency compatibility on Xbox -The nxdk submodule tracks `ReenigneArcher/nxdk`'s `codex/moonlight-runtime` branch, -which pins `ReenigneArcher/nxdk-pdclib`'s `codex/descriptor-stdio` branch. Both dependencies -are pinned to specific commits, so recursive checkout includes the required runtime support -without waiting for the upstream nxdk or PDCLib pull requests to merge. - -nxdk provides regular-file descriptors shared by POSIX I/O and stdio. Socket descriptors use -a separate range and dispatch to lwIP after network initialization. `gettimeofday()` uses -kernel timestamps with subsecond precision. - -The Xbox OpenSSL build disables POSIX descriptor I/O. Pairing uses a custom socket BIO that -leaves socket ownership with the caller. Directory enumeration and path-based `stat()` use -nxdk's working filesystem APIs directly. Stat queries return the native file identity, -64-bit size, and access, write, and metadata-change timestamps; unrepresentable timestamps -report `EOVERFLOW`. Relative paths resolve against nxdk's fixed `D:\` working directory. -FFmpeg builds its original file helpers against nxdk's descriptor APIs using its generic -platform path. Memory mapping and temporary-file creation remain disabled. +The SDK submodule tracks upstream XboxDev/nxdk, including its upstream PDCLib. Moonlight's +Xbox adapters live in `src/_nxdk_compat` and are built by `cmake/nxdk-compat.cmake`. +The local network target builds upstream lwIP with the streaming receive limits, +socket options and mDNS enabled. Checked adjustments to generated build-directory +copies preserve the nxdk thread priorities and safe packet drops on receive-pool +exhaustion; the submodule sources stay unchanged. `nxNetInit` is compiled with the +same settings so its network-interface layout matches lwIP. + +The compatibility layer provides real wall-clock, sleep and reentrant string helpers. +FFmpeg's unused POSIX descriptor/file helpers and OpenSSL's optional POSIX directory +and metadata queries fail explicitly with `ENOSYS`. Moonlight's Win32 file APIs, +standard stdio and custom OpenSSL socket BIO continue to handle saved data and pairing. +FFmpeg configure probes still link actual Xbox libraries and the local timing helpers. + +OpenSSL disables POSIX descriptor I/O; its socket BIO leaves socket ownership with +the caller. FFmpeg builds its original file helpers through its generic platform +path, with memory mapping and temporary-file creation disabled. ### CLion on Windows diff --git a/cmake/modules/GetOpenSSL.cmake b/cmake/modules/GetOpenSSL.cmake index ba56b3e..0c63a63 100644 --- a/cmake/modules/GetOpenSSL.cmake +++ b/cmake/modules/GetOpenSSL.cmake @@ -120,6 +120,7 @@ if(MOONLIGHT_OPENSSL_PLATFORM STREQUAL "XBOX") -D_exit=_Exit -include "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/openssl_compat.h" + "-I${CMAKE_SOURCE_DIR}/src/_nxdk_compat/include" "-I${NXDK_DIR}/lib" "-I${NXDK_DIR}/lib/net" "-I${NXDK_DIR}/lib/xboxrt/libc_extensions" @@ -303,8 +304,8 @@ if(MOONLIGHT_OPENSSL_PLATFORM STREQUAL "XBOX") DEPENDERS build DEPENDS "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/openssl_compat.h" - "${NXDK_DIR}/lib/xboxrt/libc_extensions/dirent.h" - "${NXDK_DIR}/lib/xboxrt/libc_extensions/sys/stat.h" + "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/include/dirent.h" + "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/include/sys/stat.h" COMMENT "Invalidate OpenSSL objects after nxdk compatibility changes" LOG ON) endif() diff --git a/cmake/moonlight-dependencies.cmake b/cmake/moonlight-dependencies.cmake index ff5e719..9204e15 100644 --- a/cmake/moonlight-dependencies.cmake +++ b/cmake/moonlight-dependencies.cmake @@ -65,27 +65,24 @@ function(_moonlight_compute_ffmpeg_signature out_var nxdk_dir ffmpeg_source_dir) set(ffmpeg_cxx_wrapper "${ARGV4}") _moonlight_get_ffmpeg_revision(ffmpeg_revision "${ffmpeg_source_dir}") + _moonlight_get_ffmpeg_revision(nxdk_revision "${nxdk_dir}") + _moonlight_get_ffmpeg_revision(pdclib_revision "${nxdk_dir}/lib/pdclib") file(SHA256 "${ffmpeg_cc_wrapper}" ffmpeg_cc_wrapper_hash) file(SHA256 "${ffmpeg_cxx_wrapper}" ffmpeg_cxx_wrapper_hash) - file(SHA256 "${nxdk_dir}/lib/xboxrt/libc_extensions/sys/types.h" ffmpeg_nxdk_types_hash) - file(SHA256 "${nxdk_dir}/lib/xboxrt/libc_extensions/sys/time.h" ffmpeg_nxdk_time_hash) - file(SHA256 "${nxdk_dir}/lib/xboxrt/libc_extensions/fcntl.h" ffmpeg_nxdk_fcntl_hash) - file(SHA256 "${nxdk_dir}/lib/xboxrt/libc_extensions/unistd.h" ffmpeg_nxdk_unistd_hash) - file(SHA256 "${nxdk_dir}/lib/xboxrt/libc_extensions/sys/stat.h" ffmpeg_nxdk_stat_hash) - file(SHA256 "${nxdk_dir}/lib/xboxrt/libc_extensions/stdio_ext_.h" ffmpeg_nxdk_stdio_hash) - file(SHA256 "${nxdk_dir}/lib/pdclib/platform/xbox/include/pdclib/_PDCLIB_config.h" ffmpeg_nxdk_pdclib_hash) + file(GLOB_RECURSE compat_inputs CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.h" "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.c") + set(compat_hashes) + foreach(input IN LISTS compat_inputs) + file(SHA256 "${input}" input_hash) + list(APPEND compat_hashes "${input}=${input_hash}") + endforeach() file(SHA256 "${CMAKE_SOURCE_DIR}/cmake/moonlight-dependencies.cmake" ffmpeg_dependency_manifest_hash) set(signature_inputs "FFMPEG_REVISION=${ffmpeg_revision}" "NXDK_DIR=${nxdk_dir}" - "NXDK_TYPES_SHA256=${ffmpeg_nxdk_types_hash}" - "NXDK_TIME_SHA256=${ffmpeg_nxdk_time_hash}" - "NXDK_FCNTL_SHA256=${ffmpeg_nxdk_fcntl_hash}" - "NXDK_UNISTD_SHA256=${ffmpeg_nxdk_unistd_hash}" - "NXDK_STAT_SHA256=${ffmpeg_nxdk_stat_hash}" - "NXDK_STDIO_SHA256=${ffmpeg_nxdk_stdio_hash}" - "NXDK_PDCLIB_SHA256=${ffmpeg_nxdk_pdclib_hash}" + "NXDK_REVISION=${nxdk_revision}" + "PDCLIB_REVISION=${pdclib_revision}" + "COMPAT_SHA256=${compat_hashes}" "FFMPEG_PROFILE=h264-opus-xbox" "FFMPEG_TARGET_OS=none" "FFMPEG_ARCH=x86" @@ -165,6 +162,7 @@ function(_moonlight_get_ffmpeg_configure_args out_var) sh "${ffmpeg_source_shell_path}/configure" "--prefix=${ffmpeg_install_shell_path}" + "--extra-ldflags=${MOONLIGHT_NXDK_COMPAT_LIBRARY}" --enable-cross-compile --arch=x86 --cpu=i686 @@ -430,15 +428,9 @@ macro(MOONLIGHT_PREPARE_COMMON_DEPENDENCIES) set(MOONLIGHT_NXDK_NET_INCLUDE_DIR "${NXDK_DIR}/lib/net") set(MOONLIGHT_NXDK_LIBC_EXTENSIONS_DIR "${NXDK_DIR}/lib/xboxrt/libc_extensions") set(MOONLIGHT_NXDK_LWIP_POSIX_COMPAT_DIR "${NXDK_DIR}/lib/net/lwip/src/include/compat/posix") - set(MOONLIGHT_NXDK_LWIP_MDNS_SOURCES - "${NXDK_DIR}/lib/net/lwip/src/apps/mdns/mdns.c" - "${NXDK_DIR}/lib/net/lwip/src/apps/mdns/mdns_domain.c" - "${NXDK_DIR}/lib/net/lwip/src/apps/mdns/mdns_out.c" - ) - if(TARGET enet) target_compile_definitions(enet PRIVATE NXDK) - target_link_libraries(enet PUBLIC NXDK::NXDK NXDK::Net) + target_link_libraries(enet PUBLIC NXDK::NXDK NXDK::Net moonlight_nxdk_compat) target_include_directories(enet PRIVATE "${MOONLIGHT_NXDK_NET_INCLUDE_DIR}" "${MOONLIGHT_NXDK_LIBC_EXTENSIONS_DIR}" @@ -448,6 +440,7 @@ macro(MOONLIGHT_PREPARE_COMMON_DEPENDENCIES) if(TARGET moonlight-common-c) target_compile_definitions(moonlight-common-c PRIVATE NXDK) + target_link_libraries(moonlight-common-c PUBLIC moonlight_nxdk_compat NXDK::Net) target_include_directories(moonlight-common-c PRIVATE "${MOONLIGHT_NXDK_NET_INCLUDE_DIR}" "${MOONLIGHT_NXDK_LIBC_EXTENSIONS_DIR}" diff --git a/cmake/nxdk-compat.cmake b/cmake/nxdk-compat.cmake new file mode 100644 index 0000000..54372cf --- /dev/null +++ b/cmake/nxdk-compat.cmake @@ -0,0 +1,86 @@ +# Build Moonlight's adapters against unmodified upstream nxdk sources. +include_guard(GLOBAL) + +# Apply a checked port adjustment to a generated copy, never to the submodule. +function(_moonlight_replace_port_text variable before after) + string(FIND "${${variable}}" "${before}" position) + if(position EQUAL -1) + message(FATAL_ERROR "nxdk port changed; review Moonlight's network adapter: ${before}") + endif() + string(REPLACE "${before}" "${after}" result "${${variable}}") + set(${variable} "${result}" PARENT_SCOPE) +endfunction() + +function(moonlight_prepare_nxdk_compat) + set(compat "${CMAKE_SOURCE_DIR}/src/_nxdk_compat") + set(port "${CMAKE_CURRENT_BINARY_DIR}/nxdk-compat") + file(MAKE_DIRECTORY "${port}/arch") + + # opt.h includes this before defining defaults. Keep nxdk's base settings. + configure_file("${compat}/network/lwipopts.h.in" "${port}/lwipopts.h" @ONLY) + set(sys_header "${NXDK_DIR}/lib/net/nforceif/include/arch/sys_arch.h") + set(sys_source "${NXDK_DIR}/lib/net/nforceif/src/sys_arch.c") + set(rx_source "${NXDK_DIR}/lib/net/nvnetdrv/nvnetdrv_lwip.c") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS + "${sys_header}" "${sys_source}" "${rx_source}") + file(READ "${sys_header}" text) + _moonlight_replace_port_text(text "#define SYS_MBOX_SIZE 128" "#define SYS_MBOX_SIZE 255") + file(CONFIGURE OUTPUT "${port}/arch/sys_arch.h" CONTENT "${text}" @ONLY) + + file(READ "${sys_source}" text) + _moonlight_replace_port_text(text "#include " "#include \n#include ") + _moonlight_replace_port_text(text " LWIP_UNUSED_ARG(prio);" "") + _moonlight_replace_port_text(text + " return CreateThread(NULL, stacksize, (void *)function, arg, 0, NULL);" + " HANDLE thread = CreateThread(NULL, stacksize, (void *)function, arg, 0, NULL);\n if (thread != NULL && prio != 0) {\n SetThreadPriority(thread, prio);\n }\n return thread;") + file(CONFIGURE OUTPUT "${port}/sys_arch.c" CONTENT "${text}" @ONLY) + + file(READ "${rx_source}" text) + _moonlight_replace_port_text(text + " LWIP_ASSERT(\"RX_POOL full\\n\", rx_pbuf != NULL);" + " if (rx_pbuf == NULL) {\n LINK_STATS_INC(link.memerr);\n LINK_STATS_INC(link.drop);\n nvnetdrv_rx_release(buffer);\n return;\n }") + _moonlight_replace_port_text(text + " if (g_pnetif->input(p, g_pnetif) != ERR_OK) {" + " if (g_pnetif->input(p, g_pnetif) != ERR_OK) {\n LINK_STATS_INC(link.memerr);\n LINK_STATS_INC(link.drop);") + file(CONFIGURE OUTPUT "${port}/nvnetdrv_lwip.c" CONTENT "${text}" @ONLY) + + set(LWIP_DIR "${NXDK_DIR}/lib/net/lwip") + set(LWIP_EXCLUDE_SLIPIF TRUE) + include("${LWIP_DIR}/src/Filelists.cmake") + add_library(moonlight_nxdk_net STATIC + ${lwipcore_SRCS} ${lwipcore4_SRCS} ${lwipcore6_SRCS} + ${lwipapi_SRCS} ${lwipnetif_SRCS} ${lwipmdns_SRCS} + "${NXDK_DIR}/lib/net/nvnetdrv/nvnetdrv.c" + "${port}/nvnetdrv_lwip.c" "${port}/sys_arch.c") + target_compile_definitions(moonlight_nxdk_net PRIVATE RX_BUFF_CNT=PBUF_POOL_SIZE) + target_include_directories(moonlight_nxdk_net BEFORE PUBLIC + "${port}" "${compat}/include") + target_include_directories(moonlight_nxdk_net SYSTEM PUBLIC + "${NXDK_DIR}/lib/net/lwip/src/include" + "${NXDK_DIR}/lib/net/nforceif/include" + "${NXDK_DIR}/lib/net/nvnetdrv") + + # nxNetInit owns a struct netif: it must use the same mDNS-enabled layout. + # Include it as an object so the stock libnxdk net.obj is never extracted. + add_library(moonlight_nxdk_net_init OBJECT "${NXDK_DIR}/lib/nxdk/net.c") + target_link_libraries(moonlight_nxdk_net_init PRIVATE moonlight_nxdk_net) + get_target_property(sdk_libraries NXDK::NXDK INTERFACE_LINK_LIBRARIES) + list(REMOVE_ITEM sdk_libraries nxdk_net) + set_property(TARGET NXDK::NXDK PROPERTY INTERFACE_LINK_LIBRARIES "${sdk_libraries};moonlight_nxdk_net") + set_property(TARGET NXDK::Net PROPERTY INTERFACE_LINK_LIBRARIES moonlight_nxdk_net) + + # FFmpeg configures before ordinary targets build. Build its real timing + # helpers now as well, so configure still links genuine Xbox executables. + moonlight_run_nxdk_command("Compatibility probe object" "${NXDK_DIR}" "${port}" + "${NXDK_DIR}/bin/nxdk-cc" "-I${compat}/include" + -c "${compat}/runtime.c" -o runtime.obj) + moonlight_run_nxdk_command("Compatibility probe archive" "${NXDK_DIR}" "${port}" + llvm-ar rcs compat.lib runtime.obj) + set(MOONLIGHT_NXDK_COMPAT_LIBRARY "${port}/compat.lib" PARENT_SCOPE) + add_library(moonlight_nxdk_compat STATIC "${compat}/runtime.c") + target_include_directories(moonlight_nxdk_compat PUBLIC "${compat}/include") + target_compile_options(moonlight_nxdk_compat INTERFACE + -include "${compat}/include/moonlight_posix.h") + file(GLOB_RECURSE compat_inputs CONFIGURE_DEPENDS "${compat}/*.h" "${compat}/*.c") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${compat_inputs}) +endfunction() diff --git a/cmake/nxdk.cmake b/cmake/nxdk.cmake index b3a0368..fdc355a 100644 --- a/cmake/nxdk.cmake +++ b/cmake/nxdk.cmake @@ -230,8 +230,15 @@ endfunction() function(moonlight_prepare_nxdk nxdk_dir state_dir) file(MAKE_DIRECTORY "${state_dir}") + # A changed SDK/PDClib checkout must not reuse archives from a previous fork. + execute_process(COMMAND git -C "${nxdk_dir}" rev-parse HEAD + OUTPUT_VARIABLE nxdk_revision OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND git -C "${nxdk_dir}/lib/pdclib" rev-parse HEAD + OUTPUT_VARIABLE pdclib_revision OUTPUT_STRIP_TRAILING_WHITESPACE) set(signature_inputs "NXDK_DIR=${nxdk_dir}" + "NXDK_REVISION=${nxdk_revision}" + "PDCLIB_REVISION=${pdclib_revision}" "HOST_SYSTEM=${CMAKE_HOST_SYSTEM_NAME}" "NXDK_TOOLCHAIN=${nxdk_dir}/share/toolchain-nxdk.cmake" "NXDK_ENV_MODE=cmake-driver" diff --git a/cmake/xbox-build.cmake b/cmake/xbox-build.cmake index c541e7e..e856806 100644 --- a/cmake/xbox-build.cmake +++ b/cmake/xbox-build.cmake @@ -21,6 +21,9 @@ if(NOT MOONLIGHT_SKIP_NXDK_PREP) endif() find_package(NXDK REQUIRED) +include("${CMAKE_SOURCE_DIR}/cmake/nxdk-compat.cmake") +moonlight_prepare_nxdk_compat() + find_package(NXDK_SDL2 REQUIRED) find_package(NXDK_SDL2_Image REQUIRED) find_package(NXDK_SDL2_TTF REQUIRED) @@ -66,7 +69,7 @@ add_executable(${CMAKE_PROJECT_NAME} target_sources(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/fenv_compat.cpp" - ${MOONLIGHT_NXDK_LWIP_MDNS_SOURCES} + $ ) target_include_directories(${CMAKE_PROJECT_NAME} SYSTEM PRIVATE @@ -84,6 +87,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME} NXDK::NXDK NXDK::NXDK_CXX NXDK::Net + moonlight_nxdk_compat NXDK::SDL2 NXDK::SDL2_Image NXDK::SDL2_TTF diff --git a/scripts/ffmpeg-nxdk-cc.sh b/scripts/ffmpeg-nxdk-cc.sh index 0ccd97e..7ac6e38 100644 --- a/scripts/ffmpeg-nxdk-cc.sh +++ b/scripts/ffmpeg-nxdk-cc.sh @@ -3,6 +3,7 @@ set -eu unset MSYS2_ARG_CONV_EXCL +compat_dir=$(CDPATH= cd -- "$(dirname -- "$0")/../src/_nxdk_compat" && pwd) link=1 for arg in "$@"; do @@ -22,7 +23,7 @@ if [ "$link" -eq 1 ]; then "${NXDK_DIR}/lib/xboxkrnl/libxboxkrnl.lib" fi -# Use nxdk's POSIX libc interfaces; this target has no MSVCRT. +# Use Moonlight's private adapters with stock nxdk; this target has no MSVCRT. exec clang \ -target i386-pc-win32 \ -march=pentium3 \ @@ -30,6 +31,8 @@ exec clang \ -ffreestanding \ -nostdlib \ -fno-builtin \ + -I"${compat_dir}/include" \ + -include "${compat_dir}/ffmpeg_compat.h" \ -I"${NXDK_DIR}/lib" \ -I"${NXDK_DIR}/lib/xboxrt/libc_extensions" \ -isystem "${NXDK_DIR}/lib/pdclib/include" \ diff --git a/scripts/ffmpeg-nxdk-cxx.sh b/scripts/ffmpeg-nxdk-cxx.sh index 749a248..97e0edb 100644 --- a/scripts/ffmpeg-nxdk-cxx.sh +++ b/scripts/ffmpeg-nxdk-cxx.sh @@ -3,6 +3,7 @@ set -eu unset MSYS2_ARG_CONV_EXCL +compat_dir=$(CDPATH= cd -- "$(dirname -- "$0")/../src/_nxdk_compat" && pwd) link=1 for arg in "$@"; do @@ -32,6 +33,8 @@ exec clang \ -nostdlib \ -fno-builtin \ -I"${NXDK_DIR}/lib/libcxx/include" \ + -I"${compat_dir}/include" \ + -include "${compat_dir}/ffmpeg_compat.h" \ -I"${NXDK_DIR}/lib" \ -I"${NXDK_DIR}/lib/xboxrt/libc_extensions" \ -isystem "${NXDK_DIR}/lib/pdclib/include" \ diff --git a/src/_nxdk_compat/ffmpeg_compat.h b/src/_nxdk_compat/ffmpeg_compat.h new file mode 100644 index 0000000..52d3eec --- /dev/null +++ b/src/_nxdk_compat/ffmpeg_compat.h @@ -0,0 +1,112 @@ +/** + * @file src/_nxdk_compat/ffmpeg_compat.h + * @brief Adapt optional FFmpeg file helpers without pretending Xbox has POSIX files. + * + * Moonlight supplies compressed data in memory. Normal stdio remains available; + * descriptors, mapped files and temporary files are outside this decoder build. + */ +#pragma once +#include +#include +#include + +/** + * @brief Reject an optional FFmpeg open request. + * + * @param path Requested path. + * @param flags Requested access flags. + * @param ... Unused creation mode. + * @return Always -1 with errno set to ENOSYS. + */ +static inline int moonlight_nxdk_open(const char *path, int flags, ...) { + (void) path; + (void) flags; + errno = ENOSYS; + return -1; +} + +/** @brief Keep open adaptation private to FFmpeg. */ +#define open moonlight_nxdk_open + +/** + * @brief Reject an optional FFmpeg close request. + * + * @param descriptor Unsupported file descriptor. + * @return Always -1 with errno set to ENOSYS. + */ +static inline int moonlight_nxdk_close(int descriptor) { + (void) descriptor; + errno = ENOSYS; + return -1; +} + +/** @brief Keep close adaptation private to FFmpeg. */ +#define close moonlight_nxdk_close + +/** + * @brief Reject an optional FFmpeg read request. + * + * @param descriptor Unsupported file descriptor. + * @param buffer Unmodified destination. + * @param size Requested byte count. + * @return Always -1 with errno set to ENOSYS. + */ +static inline ssize_t moonlight_nxdk_read(int descriptor, void *buffer, size_t size) { + (void) descriptor; + (void) buffer; + (void) size; + errno = ENOSYS; + return -1; +} + +/** @brief Keep read adaptation private to FFmpeg. */ +#define read moonlight_nxdk_read + +/** + * @brief Reject an optional FFmpeg fdopen request. + * + * @param descriptor Unsupported file descriptor. + * @param mode Requested stdio mode. + * @return Always NULL with errno set to ENOSYS. + */ +static inline FILE *moonlight_nxdk_fdopen(int descriptor, const char *mode) { + (void) descriptor; + (void) mode; + errno = ENOSYS; + return NULL; +} + +/** @brief Keep fdopen adaptation private to FFmpeg. */ +#define fdopen moonlight_nxdk_fdopen + +/** + * @brief Reject an optional FFmpeg access request. + * + * @param path Requested path. + * @param mode Requested permissions. + * @return Always -1 with errno set to ENOSYS. + */ +static inline int moonlight_nxdk_access(const char *path, int mode) { + (void) path; + (void) mode; + errno = ENOSYS; + return -1; +} + +/** @brief Keep access adaptation private to FFmpeg. */ +#define access moonlight_nxdk_access + +/** + * @brief Reject an optional FFmpeg isatty request. + * + * @param descriptor Unsupported terminal descriptor. + * @return Always 0 with errno set to ENOSYS. + */ +static inline int moonlight_nxdk_isatty(int descriptor) { + (void) descriptor; + errno = ENOSYS; + return 0; +} + +/** @brief Keep isatty adaptation private to FFmpeg. */ +#define isatty moonlight_nxdk_isatty diff --git a/src/_nxdk_compat/include/dirent.h b/src/_nxdk_compat/include/dirent.h new file mode 100644 index 0000000..32f95ae --- /dev/null +++ b/src/_nxdk_compat/include/dirent.h @@ -0,0 +1,49 @@ +/** + * @file src/_nxdk_compat/include/dirent.h + * @brief Reject OpenSSL's optional POSIX directory-store backend on Xbox. + */ +#pragma once +#include +#include +typedef struct moonlight_nxdk_directory DIR; ///< Opaque unsupported directory iterator. + +/** @brief Directory entry shape required to compile OpenSSL's optional backend. */ +struct dirent { + char d_name[256]; ///< Entry name; never populated by the adapter. +}; + +/** + * @brief Reject a POSIX directory open request. + * + * @param path Requested directory. + * @return Always NULL with errno set to ENOSYS. + */ +static inline DIR *opendir(const char *path) { + (void) path; + errno = ENOSYS; + return NULL; +} + +/** + * @brief Reject a POSIX directory read request. + * + * @param directory Unsupported iterator. + * @return Always NULL with errno set to ENOSYS. + */ +static inline struct dirent *readdir(DIR *directory) { + (void) directory; + errno = ENOSYS; + return NULL; +} + +/** + * @brief Reject a POSIX directory close request. + * + * @param directory Unsupported iterator. + * @return Always -1 with errno set to ENOSYS. + */ +static inline int closedir(DIR *directory) { + (void) directory; + errno = ENOSYS; + return -1; +} diff --git a/src/_nxdk_compat/include/fcntl.h b/src/_nxdk_compat/include/fcntl.h new file mode 100644 index 0000000..f5d9ac3 --- /dev/null +++ b/src/_nxdk_compat/include/fcntl.h @@ -0,0 +1,25 @@ +/** + * @file src/_nxdk_compat/include/fcntl.h + * @brief Provide the flags needed by dependency code and native lwIP fcntl. + */ +#pragma once +/** @brief Read-only file access. */ +#ifndef O_RDONLY + #define O_RDONLY 2 +#endif +/** @brief Write-only file access. */ +#ifndef O_WRONLY + #define O_WRONLY 4 +#endif +/** @brief Read/write file access. */ +#ifndef O_RDWR + #define O_RDWR (O_RDONLY | O_WRONLY) +#endif +/** @brief Create a file. */ +#define O_CREAT 0x100 +/** @brief Truncate a file. */ +#define O_TRUNC 0x200 +/** @brief Append to a file. */ +#define O_APPEND 0x400 +/** @brief Require exclusive creation. */ +#define O_EXCL 0x800 diff --git a/src/_nxdk_compat/include/memory.h b/src/_nxdk_compat/include/memory.h new file mode 100644 index 0000000..c4483ad --- /dev/null +++ b/src/_nxdk_compat/include/memory.h @@ -0,0 +1,6 @@ +/** + * @file src/_nxdk_compat/include/memory.h + * @brief Forward a dependency include path to stock nxdk. + */ +#pragma once +#include diff --git a/src/_nxdk_compat/include/moonlight_posix.h b/src/_nxdk_compat/include/moonlight_posix.h new file mode 100644 index 0000000..e3f1cb9 --- /dev/null +++ b/src/_nxdk_compat/include/moonlight_posix.h @@ -0,0 +1,33 @@ +/** + * @file src/_nxdk_compat/include/moonlight_posix.h + * @brief Declare the small POSIX subset actually used by Moonlight on Xbox. + */ +#pragma once +#include +#ifndef EHOSTDOWN + /** @brief Treat unavailable host-down errors as lwIP host-unreachable errors. */ + #define EHOSTDOWN EHOSTUNREACH +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif + /** + * @brief Split a string using caller-owned iteration state. + * + * @param string Initial mutable string, or NULL to continue. + * @param delimiters Characters separating tokens. + * @param context Caller-owned continuation pointer. + * @return Next token, or NULL when exhausted. + */ + char *strtok_r(char *string, const char *delimiters, char **context); + /** + * @brief Sleep for at least the requested number of microseconds. + * + * @param microseconds Requested duration, rounded up to milliseconds. + * @return Zero after the sleep completes. + */ + int usleep(unsigned int microseconds); +#ifdef __cplusplus +} +#endif diff --git a/src/_nxdk_compat/include/netinet/in.h b/src/_nxdk_compat/include/netinet/in.h new file mode 100644 index 0000000..ce731b8 --- /dev/null +++ b/src/_nxdk_compat/include/netinet/in.h @@ -0,0 +1,6 @@ +/** + * @file src/_nxdk_compat/include/netinet/in.h + * @brief Forward a dependency include path to stock nxdk. + */ +#pragma once +#include diff --git a/src/_nxdk_compat/include/netinet/tcp.h b/src/_nxdk_compat/include/netinet/tcp.h new file mode 100644 index 0000000..d45047a --- /dev/null +++ b/src/_nxdk_compat/include/netinet/tcp.h @@ -0,0 +1,6 @@ +/** + * @file src/_nxdk_compat/include/netinet/tcp.h + * @brief Forward a dependency include path to stock nxdk. + */ +#pragma once +#include diff --git a/src/_nxdk_compat/include/poll.h b/src/_nxdk_compat/include/poll.h new file mode 100644 index 0000000..c306104 --- /dev/null +++ b/src/_nxdk_compat/include/poll.h @@ -0,0 +1,6 @@ +/** + * @file src/_nxdk_compat/include/poll.h + * @brief Forward a dependency include path to stock nxdk. + */ +#pragma once +#include diff --git a/src/_nxdk_compat/include/sys/ioctl.h b/src/_nxdk_compat/include/sys/ioctl.h new file mode 100644 index 0000000..68f7adc --- /dev/null +++ b/src/_nxdk_compat/include/sys/ioctl.h @@ -0,0 +1,6 @@ +/** + * @file src/_nxdk_compat/include/sys/ioctl.h + * @brief Forward a dependency include path to stock nxdk. + */ +#pragma once +#include diff --git a/src/_nxdk_compat/include/sys/select.h b/src/_nxdk_compat/include/sys/select.h new file mode 100644 index 0000000..693ac28 --- /dev/null +++ b/src/_nxdk_compat/include/sys/select.h @@ -0,0 +1,6 @@ +/** + * @file src/_nxdk_compat/include/sys/select.h + * @brief Forward a dependency include path to stock nxdk. + */ +#pragma once +#include diff --git a/src/_nxdk_compat/include/sys/stat.h b/src/_nxdk_compat/include/sys/stat.h new file mode 100644 index 0000000..9ffefa4 --- /dev/null +++ b/src/_nxdk_compat/include/sys/stat.h @@ -0,0 +1,57 @@ +/** + * @file src/_nxdk_compat/include/sys/stat.h + * @brief Reject optional POSIX metadata queries; Moonlight uses Win32 file APIs. + */ +#pragma once +#include +#include + +/** @brief Minimal metadata shape for dependency code that is never used on Xbox. */ +struct stat { + mode_t st_mode; ///< File type and permissions; never populated by the adapter. + off_t st_size; ///< File size; never populated by the adapter. +}; + +/** @brief File type mask. */ +#define S_IFMT 0170000 +/** @brief Directory type bit. */ +#define S_IFDIR 0040000 +/** @brief Regular file type bit. */ +#define S_IFREG 0100000 +/** @brief Test a directory mode. */ +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +/** @brief Test a regular file mode. */ +#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) + +/** + * @brief Reject a POSIX path metadata query without touching its output. + * + * @param path Requested path. + * @param status Unmodified output record. + * @return Always -1 with errno set to ENOSYS. + */ +static inline int moonlight_nxdk_stat(const char *path, struct stat *status) { + (void) path; + (void) status; + errno = ENOSYS; + return -1; +} + +/** + * @brief Reject a POSIX descriptor metadata query without touching its output. + * + * @param descriptor Unsupported file descriptor. + * @param status Unmodified output record. + * @return Always -1 with errno set to ENOSYS. + */ +static inline int moonlight_nxdk_fstat(int descriptor, struct stat *status) { + (void) descriptor; + (void) status; + errno = ENOSYS; + return -1; +} + +/** @brief Scope path metadata adaptation to consumers of this private header. */ +#define stat(path, status) moonlight_nxdk_stat(path, status) +/** @brief Scope descriptor metadata adaptation to this private header. */ +#define fstat(descriptor, status) moonlight_nxdk_fstat(descriptor, status) diff --git a/src/_nxdk_compat/include/sys/time.h b/src/_nxdk_compat/include/sys/time.h new file mode 100644 index 0000000..43dfb01 --- /dev/null +++ b/src/_nxdk_compat/include/sys/time.h @@ -0,0 +1,25 @@ +/** + * @file src/_nxdk_compat/include/sys/time.h + * @brief Share the real Xbox wall clock with dependency and lwIP code. + */ +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + /** @brief Unix timestamp with microsecond resolution. */ + struct timeval { + long tv_sec; ///< Seconds since the Unix epoch. + long tv_usec; ///< Microseconds within the second. + }; + + /** + * @brief Read the Xbox wall clock as a Unix timestamp. + * + * @param value Timestamp destination. + * @param timezone Unused legacy timezone argument; must be NULL. + * @return Zero on success or -1 with errno on invalid arguments. + */ + int gettimeofday(struct timeval *value, void *timezone); +#ifdef __cplusplus +} +#endif diff --git a/src/_nxdk_compat/include/sys/types.h b/src/_nxdk_compat/include/sys/types.h new file mode 100644 index 0000000..4f533fd --- /dev/null +++ b/src/_nxdk_compat/include/sys/types.h @@ -0,0 +1,12 @@ +/** + * @file src/_nxdk_compat/include/sys/types.h + * @brief Types required by Moonlight's private dependency adapters. + */ +#pragma once +#include +#include +typedef int ssize_t; ///< Signed buffer length on the 32-bit Xbox. +typedef int64_t off_t; ///< File offset used only by unsupported descriptor APIs. +typedef unsigned int mode_t; ///< File mode bits for optional dependency queries. + +typedef int pid_t; ///< Identifier for the single Xbox application. diff --git a/src/_nxdk_compat/include/unistd.h b/src/_nxdk_compat/include/unistd.h new file mode 100644 index 0000000..07d02a2 --- /dev/null +++ b/src/_nxdk_compat/include/unistd.h @@ -0,0 +1,6 @@ +/** + * @file src/_nxdk_compat/include/unistd.h + * @brief Expose the real sleep helper to FFmpeg without affecting its function probes. + */ +#pragma once +#include "moonlight_posix.h" diff --git a/src/_nxdk_compat/network/lwipopts.h.in b/src/_nxdk_compat/network/lwipopts.h.in new file mode 100644 index 0000000..ee8b0fe --- /dev/null +++ b/src/_nxdk_compat/network/lwipopts.h.in @@ -0,0 +1,31 @@ +/** + * @file src/_nxdk_compat/network/lwipopts.h.in + * @brief Configure upstream nxdk's network stack for Moonlight UDP traffic. + */ +#pragma once +#include "@NXDK_DIR@/lib/net/nforceif/include/lwipopts.h" + +/** @brief Reserve per-interface storage for the mDNS responder. */ +#define LWIP_NUM_NETIF_CLIENT_DATA 1 +/** @brief Enable host discovery. */ +#define LWIP_MDNS_RESPONDER 1 +/** @brief Enable mDNS queries. */ +#define LWIP_MDNS_SEARCH 1 +#undef LWIP_IGMP +/** @brief Join multicast groups for host discovery. */ +#define LWIP_IGMP 1 +/** @brief Buffer short UDP bursts. */ +#define MEMP_NUM_PBUF 128 +/** @brief Size both packet and native receive pools consistently. */ +#define PBUF_POOL_SIZE 128 +/** @brief Run the TCP/IP worker above normal priority. */ +#define TCPIP_THREAD_PRIO 2 +/** @brief Run auxiliary network workers above normal priority. */ +#define DEFAULT_THREAD_PRIO 1 +/** @brief Support bounded socket receives. */ +#define LWIP_SO_RCVTIMEO 1 +/** @brief Allow Moonlight to tune socket receive queues. */ +#define LWIP_SO_RCVBUF 1 +/** @brief Share Moonlight's timeval declaration with socket consumers. */ +#define LWIP_TIMEVAL_PRIVATE 0 +#include diff --git a/src/_nxdk_compat/runtime.c b/src/_nxdk_compat/runtime.c new file mode 100644 index 0000000..1f5de9f --- /dev/null +++ b/src/_nxdk_compat/runtime.c @@ -0,0 +1,58 @@ +/** + * @file src/_nxdk_compat/runtime.c + * @brief Implement Moonlight's timing and reentrant string helpers on stock nxdk. + */ +#include "include/moonlight_posix.h" + +#include +#include +#include +#include +#include +#include + +int gettimeofday(struct timeval *value, void *timezone) { + if (value == NULL || timezone != NULL) { + errno = EINVAL; + return -1; + } + LARGE_INTEGER now; + KeQuerySystemTime(&now); + const int64_t ticks = now.QuadPart - INT64_C(116444736000000000); + int64_t seconds = ticks / INT64_C(10000000); + int64_t remainder = ticks % INT64_C(10000000); + if (remainder < 0) { + --seconds; + remainder += INT64_C(10000000); + } + if (seconds < LONG_MIN || seconds > LONG_MAX) { + errno = EOVERFLOW; + return -1; + } + value->tv_sec = (long) seconds; + value->tv_usec = (long) (remainder / 10); + return 0; +} + +char *strtok_r(char *string, const char *delimiters, char **context) { + char *token = string != NULL ? string : *context; + if (token == NULL) { + return NULL; + } + token += strspn(token, delimiters); + if (*token == '\0') { + *context = token; + return NULL; + } + char *end = token + strcspn(token, delimiters); + if (*end != '\0') { + *end++ = '\0'; + } + *context = end; + return token; +} + +int usleep(unsigned int microseconds) { + Sleep(microseconds / 1000U + (microseconds % 1000U != 0)); + return 0; +} diff --git a/third-party/nxdk b/third-party/nxdk index 4abc42a..fafbe41 160000 --- a/third-party/nxdk +++ b/third-party/nxdk @@ -1 +1 @@ -Subproject commit 4abc42a15dcf18ebff3b7b9f7b5a27cd2e603fe9 +Subproject commit fafbe41b48fa00a31b79dd49ad1f86a30adcdd9e From ccc198788abfd29407dbb69ee3e451c917b419ee Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Fri, 13 Nov 2026 00:09:28 -0500 Subject: [PATCH 2/4] refactor(xbox): apply network port changes from a patch --- README.md | 7 ++- cmake/nxdk-compat.cmake | 70 ++++++++++----------- src/_nxdk_compat/network/.gitattributes | 2 + src/_nxdk_compat/network/nxdk-network.patch | 65 +++++++++++++++++++ 4 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 src/_nxdk_compat/network/.gitattributes create mode 100644 src/_nxdk_compat/network/nxdk-network.patch diff --git a/README.md b/README.md index f261144..265eb2e 100644 --- a/README.md +++ b/README.md @@ -179,9 +179,10 @@ Coverage should come from this host-native test build instead of the cross-compi The SDK submodule tracks upstream XboxDev/nxdk, including its upstream PDCLib. Moonlight's Xbox adapters live in `src/_nxdk_compat` and are built by `cmake/nxdk-compat.cmake`. The local network target builds upstream lwIP with the streaming receive limits, -socket options and mDNS enabled. Checked adjustments to generated build-directory -copies preserve the nxdk thread priorities and safe packet drops on receive-pool -exhaustion; the submodule sources stay unchanged. `nxNetInit` is compiled with the +socket options and mDNS enabled. The `network/nxdk-network.patch` compatibility +patch is applied with `git apply` to build-directory copies, preserving thread +priorities and safe packet drops on receive-pool exhaustion. The submodule +sources stay unchanged. `nxNetInit` is compiled with the same settings so its network-interface layout matches lwIP. The compatibility layer provides real wall-clock, sleep and reentrant string helpers. diff --git a/cmake/nxdk-compat.cmake b/cmake/nxdk-compat.cmake index 54372cf..93c7813 100644 --- a/cmake/nxdk-compat.cmake +++ b/cmake/nxdk-compat.cmake @@ -1,48 +1,47 @@ # Build Moonlight's adapters against unmodified upstream nxdk sources. include_guard(GLOBAL) -# Apply a checked port adjustment to a generated copy, never to the submodule. -function(_moonlight_replace_port_text variable before after) - string(FIND "${${variable}}" "${before}" position) - if(position EQUAL -1) - message(FATAL_ERROR "nxdk port changed; review Moonlight's network adapter: ${before}") +# Apply the network patch to disposable copies, then publish only changed files. +function(_moonlight_patch_nxdk_network port patch_file) + find_package(Git REQUIRED) + set(work "${port}/patch-work") + set(port_files + lib/net/nforceif/include/arch/sys_arch.h + lib/net/nforceif/src/sys_arch.c + lib/net/nvnetdrv/nvnetdrv_lwip.c) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${patch_file}") + foreach(source IN LISTS port_files) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${NXDK_DIR}/${source}") + configure_file("${NXDK_DIR}/${source}" "${work}/${source}" COPYONLY) + endforeach() + + # An explicit work tree confines git apply to these copies, including when + # the build directory is inside the Moonlight checkout. Normalize CRLF on + # input and write LF so patching is independent of the user's Git settings. + execute_process( + COMMAND "${GIT_EXECUTABLE}" -c core.autocrlf=input "--work-tree=${work}" + apply --whitespace=error "${patch_file}" + WORKING_DIRECTORY "${work}" + RESULT_VARIABLE patch_result + OUTPUT_VARIABLE patch_output + ERROR_VARIABLE patch_error) + if(NOT patch_result EQUAL 0) + message(FATAL_ERROR + "Failed to apply Moonlight's nxdk network patch; review it against the selected SDK.\n" + "${patch_output}${patch_error}") endif() - string(REPLACE "${before}" "${after}" result "${${variable}}") - set(${variable} "${result}" PARENT_SCOPE) + foreach(source IN LISTS port_files) + configure_file("${work}/${source}" "${port}/${source}" COPYONLY) + endforeach() endfunction() function(moonlight_prepare_nxdk_compat) set(compat "${CMAKE_SOURCE_DIR}/src/_nxdk_compat") set(port "${CMAKE_CURRENT_BINARY_DIR}/nxdk-compat") - file(MAKE_DIRECTORY "${port}/arch") + _moonlight_patch_nxdk_network("${port}" "${compat}/network/nxdk-network.patch") # opt.h includes this before defining defaults. Keep nxdk's base settings. configure_file("${compat}/network/lwipopts.h.in" "${port}/lwipopts.h" @ONLY) - set(sys_header "${NXDK_DIR}/lib/net/nforceif/include/arch/sys_arch.h") - set(sys_source "${NXDK_DIR}/lib/net/nforceif/src/sys_arch.c") - set(rx_source "${NXDK_DIR}/lib/net/nvnetdrv/nvnetdrv_lwip.c") - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS - "${sys_header}" "${sys_source}" "${rx_source}") - file(READ "${sys_header}" text) - _moonlight_replace_port_text(text "#define SYS_MBOX_SIZE 128" "#define SYS_MBOX_SIZE 255") - file(CONFIGURE OUTPUT "${port}/arch/sys_arch.h" CONTENT "${text}" @ONLY) - - file(READ "${sys_source}" text) - _moonlight_replace_port_text(text "#include " "#include \n#include ") - _moonlight_replace_port_text(text " LWIP_UNUSED_ARG(prio);" "") - _moonlight_replace_port_text(text - " return CreateThread(NULL, stacksize, (void *)function, arg, 0, NULL);" - " HANDLE thread = CreateThread(NULL, stacksize, (void *)function, arg, 0, NULL);\n if (thread != NULL && prio != 0) {\n SetThreadPriority(thread, prio);\n }\n return thread;") - file(CONFIGURE OUTPUT "${port}/sys_arch.c" CONTENT "${text}" @ONLY) - - file(READ "${rx_source}" text) - _moonlight_replace_port_text(text - " LWIP_ASSERT(\"RX_POOL full\\n\", rx_pbuf != NULL);" - " if (rx_pbuf == NULL) {\n LINK_STATS_INC(link.memerr);\n LINK_STATS_INC(link.drop);\n nvnetdrv_rx_release(buffer);\n return;\n }") - _moonlight_replace_port_text(text - " if (g_pnetif->input(p, g_pnetif) != ERR_OK) {" - " if (g_pnetif->input(p, g_pnetif) != ERR_OK) {\n LINK_STATS_INC(link.memerr);\n LINK_STATS_INC(link.drop);") - file(CONFIGURE OUTPUT "${port}/nvnetdrv_lwip.c" CONTENT "${text}" @ONLY) set(LWIP_DIR "${NXDK_DIR}/lib/net/lwip") set(LWIP_EXCLUDE_SLIPIF TRUE) @@ -51,10 +50,11 @@ function(moonlight_prepare_nxdk_compat) ${lwipcore_SRCS} ${lwipcore4_SRCS} ${lwipcore6_SRCS} ${lwipapi_SRCS} ${lwipnetif_SRCS} ${lwipmdns_SRCS} "${NXDK_DIR}/lib/net/nvnetdrv/nvnetdrv.c" - "${port}/nvnetdrv_lwip.c" "${port}/sys_arch.c") + "${port}/lib/net/nvnetdrv/nvnetdrv_lwip.c" + "${port}/lib/net/nforceif/src/sys_arch.c") target_compile_definitions(moonlight_nxdk_net PRIVATE RX_BUFF_CNT=PBUF_POOL_SIZE) target_include_directories(moonlight_nxdk_net BEFORE PUBLIC - "${port}" "${compat}/include") + "${port}/lib/net/nforceif/include" "${port}" "${compat}/include") target_include_directories(moonlight_nxdk_net SYSTEM PUBLIC "${NXDK_DIR}/lib/net/lwip/src/include" "${NXDK_DIR}/lib/net/nforceif/include" diff --git a/src/_nxdk_compat/network/.gitattributes b/src/_nxdk_compat/network/.gitattributes new file mode 100644 index 0000000..ff230fe --- /dev/null +++ b/src/_nxdk_compat/network/.gitattributes @@ -0,0 +1,2 @@ +# Empty context lines in unified diffs have a required space prefix. +*.patch text eol=lf whitespace=-blank-at-eol diff --git a/src/_nxdk_compat/network/nxdk-network.patch b/src/_nxdk_compat/network/nxdk-network.patch new file mode 100644 index 0000000..d307abe --- /dev/null +++ b/src/_nxdk_compat/network/nxdk-network.patch @@ -0,0 +1,65 @@ +diff --git a/lib/net/nforceif/include/arch/sys_arch.h b/lib/net/nforceif/include/arch/sys_arch.h +--- a/lib/net/nforceif/include/arch/sys_arch.h ++++ b/lib/net/nforceif/include/arch/sys_arch.h +@@ -73,7 +73,7 @@ + /* let sys.h use binary semaphores for mutexes */ + #define LWIP_COMPAT_MUTEX 1 + +-#define SYS_MBOX_SIZE 128 ++#define SYS_MBOX_SIZE 255 + + typedef struct { + volatile int first, last; +diff --git a/lib/net/nforceif/src/sys_arch.c b/lib/net/nforceif/src/sys_arch.c +--- a/lib/net/nforceif/src/sys_arch.c ++++ b/lib/net/nforceif/src/sys_arch.c +@@ -39,6 +39,7 @@ + + #include + #include ++#include + + #include + +@@ -68,9 +69,12 @@ + sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio) + { + LWIP_UNUSED_ARG(name); +- LWIP_UNUSED_ARG(prio); +- +- return CreateThread(NULL, stacksize, (void *)function, arg, 0, NULL); ++ ++ HANDLE thread = CreateThread(NULL, stacksize, (void *)function, arg, 0, NULL); ++ if (thread != NULL && prio != 0) { ++ SetThreadPriority(thread, prio); ++ } ++ return thread; + } + + err_t +diff --git a/lib/net/nvnetdrv/nvnetdrv_lwip.c b/lib/net/nvnetdrv/nvnetdrv_lwip.c +--- a/lib/net/nvnetdrv/nvnetdrv_lwip.c ++++ b/lib/net/nvnetdrv/nvnetdrv_lwip.c +@@ -70,7 +70,12 @@ + void rx_callback (void *buffer, uint16_t length) + { + rx_pbuf_t *rx_pbuf = (rx_pbuf_t *)LWIP_MEMPOOL_ALLOC(RX_POOL); +- LWIP_ASSERT("RX_POOL full\n", rx_pbuf != NULL); ++ if (rx_pbuf == NULL) { ++ LINK_STATS_INC(link.memerr); ++ LINK_STATS_INC(link.drop); ++ nvnetdrv_rx_release(buffer); ++ return; ++ } + rx_pbuf->p.custom_free_function = rx_pbuf_free_callback; + rx_pbuf->buff = buffer; + struct pbuf *p = pbuf_alloced_custom(PBUF_RAW, +@@ -81,6 +86,8 @@ + NVNET_RX_BUFF_LEN - ETH_PAD_SIZE); + + if (g_pnetif->input(p, g_pnetif) != ERR_OK) { ++ LINK_STATS_INC(link.memerr); ++ LINK_STATS_INC(link.drop); + pbuf_free(p); + } + } From 850bbd11e8de0c3d777c3370718a2685ac098192 Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Fri, 13 Nov 2026 00:32:53 -0500 Subject: [PATCH 3/4] build(xbox): compile nxdk from an isolated source copy --- CMakeLists.txt | 10 ++-- CMakePresets.json | 8 +-- README.md | 13 +++- cmake/moonlight-dependencies.cmake | 4 +- cmake/nxdk-compat.cmake | 5 +- cmake/nxdk-source.cmake | 96 ++++++++++++++++++++++++++++++ cmake/nxdk-toolchain.cmake | 16 +++++ cmake/nxdk.cmake | 28 +++++---- cmake/run-child-build.cmake | 6 +- cmake/xbox-build.cmake | 9 ++- 10 files changed, 158 insertions(+), 37 deletions(-) create mode 100644 cmake/nxdk-source.cmake create mode 100644 cmake/nxdk-toolchain.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c4b8fa4..df14b45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,6 @@ if(MOONLIGHT_BUILD_KIND STREQUAL "XBOX") set(CMAKE_CXX_STANDARD_REQUIRED ON) option(BUILD_DOCS "Build documentation" OFF) - option(MOONLIGHT_SKIP_NXDK_PREP "Skip nxdk bootstrap during the internal Xbox child configure" OFF) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/xbox-build.cmake") return() @@ -72,10 +71,13 @@ endif() if(BUILD_XBOX) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/nxdk.cmake") - moonlight_resolve_nxdk_dir(MOONLIGHT_NXDK_DIR) - moonlight_prepare_nxdk("${MOONLIGHT_NXDK_DIR}" "${CMAKE_BINARY_DIR}/nxdk-bootstrap") + moonlight_resolve_nxdk_dir(source_nxdk_dir) + set(nxdk_build_dir "${MOONLIGHT_NXDK_BUILD_DIR}") + moonlight_stage_nxdk("${source_nxdk_dir}" "${nxdk_build_dir}") + moonlight_prepare_nxdk("${nxdk_build_dir}" "${nxdk_build_dir}/.moonlight-bootstrap") moonlight_add_xbox_build( - NXDK_DIR "${MOONLIGHT_NXDK_DIR}" + NXDK_DIR "${nxdk_build_dir}" + SOURCE_NXDK_DIR "${source_nxdk_dir}" BINARY_DIR "${CMAKE_BINARY_DIR}/xbox" ) endif() diff --git a/CMakePresets.json b/CMakePresets.json index db3717a..8a6dd51 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -40,12 +40,11 @@ "displayName": "Xbox Release (mingw64)", "description": "Direct nxdk Xbox configure for IDE/code-model support on Xbox-only sources", "generator": "Unix Makefiles", - "toolchainFile": "${sourceDir}/third-party/nxdk/share/toolchain-nxdk.cmake", + "toolchainFile": "${sourceDir}/cmake/nxdk-toolchain.cmake", "binaryDir": "${sourceDir}/cmake-build-xbox-release", "environment": { "CHERE_INVOKING": "1", - "MSYSTEM": "MINGW64", - "NXDK_DIR": "${sourceDir}/third-party/nxdk" + "MSYSTEM": "MINGW64" }, "cacheVariables": { "BUILD_DOCS": "OFF", @@ -55,8 +54,7 @@ "CMAKE_MAKE_PROGRAM": "C:/msys64/usr/bin/make.exe", "CMAKE_TRY_COMPILE_TARGET_TYPE": "STATIC_LIBRARY", "MOONLIGHT_BUILD_KIND": "XBOX", - "MOONLIGHT_SKIP_NXDK_PREP": "ON", - "NXDK_DIR": "${sourceDir}/third-party/nxdk" + "MOONLIGHT_NXDK_DIR": "${sourceDir}/third-party/nxdk" } }, { diff --git a/README.md b/README.md index 265eb2e..f49794c 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ brew install "${dependencies[@]}" ### Configure -Configure the top-level project with the normal host toolchain. CMake uses the vendored `third-party/nxdk` checkout, bootstraps the required `nxdk` outputs, builds the host-native tests with the standard compiler/linker, and drives the Xbox build through an internal child configure that reuses the stock `nxdk` toolchain. +Configure the top-level project with the normal host toolchain. CMake uses the vendored `third-party/nxdk` checkout, copies its tracked sources and nested submodules into the build directory, bootstraps the required `nxdk` outputs there, builds the host-native tests with the standard compiler/linker, and drives the Xbox build through an internal child configure that reuses the stock `nxdk` toolchain. For host and Xbox builds, CMake checks whether the compiler supports Clang's `unused-but-set-global` warning. When supported, this warning remains nonfatal for `moonlight-common-c`, whose debug counters are read only by assertions that are disabled in release builds. Other warnings retain the dependency's existing error policy. @@ -178,12 +178,19 @@ Coverage should come from this host-native test build instead of the cross-compi The SDK submodule tracks upstream XboxDev/nxdk, including its upstream PDCLib. Moonlight's Xbox adapters live in `src/_nxdk_compat` and are built by `cmake/nxdk-compat.cmake`. +All SDK libraries, host tools and generated lwIP files are built under the build +directory, including for direct Xbox presets. `cmake/nxdk-toolchain.cmake` prepares +that copy before compiler checks and then loads the stock nxdk toolchain. SDK +revision changes and local edits to tracked SDK files refresh the copy; unrelated +untracked files and existing build products are excluded. `MOONLIGHT_NXDK_DIR` +selects the source checkout; `MOONLIGHT_NXDK_BUILD_DIR` selects the build copy. + The local network target builds upstream lwIP with the streaming receive limits, socket options and mDNS enabled. The `network/nxdk-network.patch` compatibility patch is applied with `git apply` to build-directory copies, preserving thread priorities and safe packet drops on receive-pool exhaustion. The submodule -sources stay unchanged. `nxNetInit` is compiled with the -same settings so its network-interface layout matches lwIP. +sources stay unchanged. `nxNetInit` is compiled with the same settings so its +network-interface layout matches lwIP. The compatibility layer provides real wall-clock, sleep and reentrant string helpers. FFmpeg's unused POSIX descriptor/file helpers and OpenSSL's optional POSIX directory diff --git a/cmake/moonlight-dependencies.cmake b/cmake/moonlight-dependencies.cmake index 9204e15..2796253 100644 --- a/cmake/moonlight-dependencies.cmake +++ b/cmake/moonlight-dependencies.cmake @@ -65,8 +65,7 @@ function(_moonlight_compute_ffmpeg_signature out_var nxdk_dir ffmpeg_source_dir) set(ffmpeg_cxx_wrapper "${ARGV4}") _moonlight_get_ffmpeg_revision(ffmpeg_revision "${ffmpeg_source_dir}") - _moonlight_get_ffmpeg_revision(nxdk_revision "${nxdk_dir}") - _moonlight_get_ffmpeg_revision(pdclib_revision "${nxdk_dir}/lib/pdclib") + file(READ "${nxdk_dir}/.moonlight-source.signature" nxdk_revision) file(SHA256 "${ffmpeg_cc_wrapper}" ffmpeg_cc_wrapper_hash) file(SHA256 "${ffmpeg_cxx_wrapper}" ffmpeg_cxx_wrapper_hash) file(GLOB_RECURSE compat_inputs CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.h" "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.c") @@ -81,7 +80,6 @@ function(_moonlight_compute_ffmpeg_signature out_var nxdk_dir ffmpeg_source_dir) "FFMPEG_REVISION=${ffmpeg_revision}" "NXDK_DIR=${nxdk_dir}" "NXDK_REVISION=${nxdk_revision}" - "PDCLIB_REVISION=${pdclib_revision}" "COMPAT_SHA256=${compat_hashes}" "FFMPEG_PROFILE=h264-opus-xbox" "FFMPEG_TARGET_OS=none" diff --git a/cmake/nxdk-compat.cmake b/cmake/nxdk-compat.cmake index 93c7813..5cc42fa 100644 --- a/cmake/nxdk-compat.cmake +++ b/cmake/nxdk-compat.cmake @@ -35,6 +35,7 @@ function(_moonlight_patch_nxdk_network port patch_file) endforeach() endfunction() +# Build Moonlight's private network port and the runtime used by dependencies. function(moonlight_prepare_nxdk_compat) set(compat "${CMAKE_SOURCE_DIR}/src/_nxdk_compat") set(port "${CMAKE_CURRENT_BINARY_DIR}/nxdk-compat") @@ -43,8 +44,8 @@ function(moonlight_prepare_nxdk_compat) # opt.h includes this before defining defaults. Keep nxdk's base settings. configure_file("${compat}/network/lwipopts.h.in" "${port}/lwipopts.h" @ONLY) - set(LWIP_DIR "${NXDK_DIR}/lib/net/lwip") - set(LWIP_EXCLUDE_SLIPIF TRUE) + set(LWIP_DIR "${NXDK_DIR}/lib/net/lwip") # cmake-lint: disable=C0103 + set(LWIP_EXCLUDE_SLIPIF TRUE) # cmake-lint: disable=C0103 include("${LWIP_DIR}/src/Filelists.cmake") add_library(moonlight_nxdk_net STATIC ${lwipcore_SRCS} ${lwipcore4_SRCS} ${lwipcore6_SRCS} diff --git a/cmake/nxdk-source.cmake b/cmake/nxdk-source.cmake new file mode 100644 index 0000000..9234f2a --- /dev/null +++ b/cmake/nxdk-source.cmake @@ -0,0 +1,96 @@ +# Keep all nxdk-generated files in an owned build-directory copy. +include_guard(GLOBAL) + +# Fingerprint the SDK revision, nested checkouts and local tracked edits. +function(_moonlight_nxdk_source_state source out_signature out_files) + execute_process(COMMAND "${GIT_EXECUTABLE}" -C "${source}" rev-parse HEAD + OUTPUT_VARIABLE revision OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY) + execute_process(COMMAND "${GIT_EXECUTABLE}" -C "${source}" submodule status --recursive + OUTPUT_VARIABLE submodules COMMAND_ERROR_IS_FATAL ANY) + if(submodules MATCHES "(^|\n)-") + message(FATAL_ERROR "Initialize nxdk's submodules with git submodule update --init --recursive") + endif() + execute_process(COMMAND "${GIT_EXECUTABLE}" -C "${source}" status + --porcelain --untracked-files=no --ignore-submodules=untracked + OUTPUT_VARIABLE dirty COMMAND_ERROR_IS_FATAL ANY) + set(inputs "${source}\n${revision}\n${submodules}") + execute_process(COMMAND "${GIT_EXECUTABLE}" -C "${source}" + -c core.quotepath=false ls-files --recurse-submodules + OUTPUT_VARIABLE files OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY) + string(REPLACE "\n" ";" files "${files}") + # Preserve local edits to tracked SDK files as well as committed revisions. + if(NOT dirty STREQUAL "") + foreach(file IN LISTS files) + if(IS_SYMLINK "${source}/${file}") + file(READ_SYMLINK "${source}/${file}" link) + string(SHA256 hash "symlink:${link}") + elseif(EXISTS "${source}/${file}") + file(SHA256 "${source}/${file}" hash) + else() + set(hash deleted) + endif() + string(APPEND inputs "${file}=${hash}\n") + endforeach() + endif() + string(SHA256 signature "${inputs}") + set(${out_signature} "${signature}" PARENT_SCOPE) + set(${out_files} "${files}" PARENT_SCOPE) +endfunction() + +# Reuse an unchanged SDK copy or replace its owned build directory with tracked sources. +function(moonlight_stage_nxdk source destination) + find_package(Git REQUIRED) + get_filename_component(source "${source}" REALPATH) + cmake_path(ABSOLUTE_PATH destination NORMALIZE) + cmake_path(IS_PREFIX source "${destination}" NORMALIZE inside_source) + if(inside_source) + message(FATAL_ERROR "The nxdk build copy must be outside its source checkout") + endif() + + # Toolchain files can be loaded more than once during a single configure. + get_property(staged GLOBAL PROPERTY MOONLIGHT_STAGED_NXDK) + if(staged STREQUAL "${source}|${destination}") + return() + endif() + _moonlight_nxdk_source_state("${source}" signature files) + set(marker "${destination}/.moonlight-nxdk-copy") + set(stamp "${destination}/.moonlight-source.signature") + if(EXISTS "${marker}" AND EXISTS "${stamp}") + file(READ "${stamp}" previous) + if(previous STREQUAL signature) + set_property(GLOBAL PROPERTY MOONLIGHT_STAGED_NXDK "${source}|${destination}") + return() + endif() + endif() + + if(EXISTS "${destination}") + # Only replace a directory created by this function. Resolve symlinks + # before deletion so a build-path alias cannot target the SDK checkout. + if(NOT EXISTS "${marker}") + message(FATAL_ERROR "Refusing to replace an existing directory not owned by Moonlight: ${destination}") + endif() + file(READ "${marker}" owner) + if(NOT owner STREQUAL "Moonlight nxdk build copy\n") + message(FATAL_ERROR "Refusing to replace a directory with an invalid ownership marker: ${destination}") + endif() + get_filename_component(resolved_destination "${destination}" REALPATH) + cmake_path(IS_PREFIX source "${resolved_destination}" NORMALIZE inside_source) + if(inside_source OR NOT resolved_destination STREQUAL destination) + message(FATAL_ERROR "Refusing to replace an aliased nxdk build directory: ${destination}") + endif() + file(REMOVE_RECURSE "${destination}") + endif() + message(STATUS "Copying nxdk tracked sources to ${destination}") + file(MAKE_DIRECTORY "${destination}") + file(WRITE "${marker}" "Moonlight nxdk build copy\n") + foreach(file IN LISTS files) + if(EXISTS "${source}/${file}" OR IS_SYMLINK "${source}/${file}") + get_filename_component(parent "${destination}/${file}" DIRECTORY) + file(COPY "${source}/${file}" DESTINATION "${parent}") + endif() + endforeach() + file(WRITE "${stamp}" "${signature}") + set_property(GLOBAL PROPERTY MOONLIGHT_STAGED_NXDK "${source}|${destination}") +endfunction() diff --git a/cmake/nxdk-toolchain.cmake b/cmake/nxdk-toolchain.cmake new file mode 100644 index 0000000..d0c656a --- /dev/null +++ b/cmake/nxdk-toolchain.cmake @@ -0,0 +1,16 @@ +# Stage nxdk before CMake runs compiler checks, then use its stock toolchain. +include("${CMAKE_CURRENT_LIST_DIR}/nxdk-source.cmake") +get_filename_component(moonlight_source "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE) +set(MOONLIGHT_NXDK_DIR "${moonlight_source}/third-party/nxdk" CACHE PATH "Path to the nxdk source checkout") +set(MOONLIGHT_NXDK_BUILD_DIR "${CMAKE_BINARY_DIR}/nxdk" CACHE PATH "Build-directory copy of nxdk") +cmake_path(ABSOLUTE_PATH MOONLIGHT_NXDK_DIR BASE_DIRECTORY "${moonlight_source}" NORMALIZE) +cmake_path(ABSOLUTE_PATH MOONLIGHT_NXDK_BUILD_DIR BASE_DIRECTORY "${CMAKE_BINARY_DIR}" NORMALIZE) +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES MOONLIGHT_NXDK_DIR MOONLIGHT_NXDK_BUILD_DIR) +get_property(in_try_compile GLOBAL PROPERTY IN_TRY_COMPILE) +if(NOT in_try_compile) + moonlight_stage_nxdk("${MOONLIGHT_NXDK_DIR}" "${MOONLIGHT_NXDK_BUILD_DIR}") +endif() +set(NXDK_DIR "${MOONLIGHT_NXDK_BUILD_DIR}" CACHE PATH "Prepared nxdk build copy" FORCE) +set(ENV{NXDK_DIR} "${NXDK_DIR}") +include("${NXDK_DIR}/share/toolchain-nxdk.cmake") diff --git a/cmake/nxdk.cmake b/cmake/nxdk.cmake index fdc355a..eb29f7e 100644 --- a/cmake/nxdk.cmake +++ b/cmake/nxdk.cmake @@ -4,9 +4,12 @@ include_guard(GLOBAL) include(CMakeParseArguments) include("${CMAKE_CURRENT_LIST_DIR}/msys2.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/nxdk-source.cmake") set(MOONLIGHT_NXDK_DIR "${CMAKE_SOURCE_DIR}/third-party/nxdk" CACHE PATH "Path to the vendored nxdk checkout") cmake_path(ABSOLUTE_PATH MOONLIGHT_NXDK_DIR BASE_DIRECTORY "${CMAKE_SOURCE_DIR}" NORMALIZE) +set(MOONLIGHT_NXDK_BUILD_DIR "${CMAKE_BINARY_DIR}/nxdk" CACHE PATH "Build-directory copy of nxdk") +cmake_path(ABSOLUTE_PATH MOONLIGHT_NXDK_BUILD_DIR BASE_DIRECTORY "${CMAKE_BINARY_DIR}" NORMALIZE) # Resolve and validate the nxdk directory, returning its absolute path. function(moonlight_resolve_nxdk_dir out_var) @@ -155,7 +158,8 @@ function(_moonlight_run_nxdk_make nxdk_dir description) _moonlight_get_xbox_make_program(make_program) endif() - moonlight_run_nxdk_command("${description}" "${nxdk_dir}" "${nxdk_dir}" "${make_program}" ${ARGN}) + # Relative input paths keep the Windows archiver command below its argv limit. + moonlight_run_nxdk_command("${description}" "${nxdk_dir}" "${nxdk_dir}" "${make_program}" NXDK_DIR=. ${ARGN}) endfunction() # Report whether any listed output path is missing. @@ -230,15 +234,10 @@ endfunction() function(moonlight_prepare_nxdk nxdk_dir state_dir) file(MAKE_DIRECTORY "${state_dir}") - # A changed SDK/PDClib checkout must not reuse archives from a previous fork. - execute_process(COMMAND git -C "${nxdk_dir}" rev-parse HEAD - OUTPUT_VARIABLE nxdk_revision OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND git -C "${nxdk_dir}/lib/pdclib" rev-parse HEAD - OUTPUT_VARIABLE pdclib_revision OUTPUT_STRIP_TRAILING_WHITESPACE) + file(READ "${nxdk_dir}/.moonlight-source.signature" nxdk_revision) set(signature_inputs "NXDK_DIR=${nxdk_dir}" "NXDK_REVISION=${nxdk_revision}" - "PDCLIB_REVISION=${pdclib_revision}" "HOST_SYSTEM=${CMAKE_HOST_SYSTEM_NAME}" "NXDK_TOOLCHAIN=${nxdk_dir}/share/toolchain-nxdk.cmake" "NXDK_ENV_MODE=cmake-driver" @@ -247,10 +246,14 @@ function(moonlight_prepare_nxdk nxdk_dir state_dir) string(SHA256 signature "${signature_text}") set(signature_file "${state_dir}/bootstrap.signature") - set(cxbe_path "${nxdk_dir}/tools/cxbe/cxbe") + set(tool_suffix "") + if(CMAKE_HOST_WIN32) + set(tool_suffix ".exe") + endif() + set(cxbe_path "${nxdk_dir}/tools/cxbe/cxbe${tool_suffix}") set(extract_xiso_source_dir "${nxdk_dir}/tools/extract-xiso") set(extract_xiso_build_dir "${extract_xiso_source_dir}/build") - set(extract_xiso_path "${extract_xiso_build_dir}/extract-xiso") + set(extract_xiso_path "${extract_xiso_build_dir}/extract-xiso${tool_suffix}") set(required_libraries "${nxdk_dir}/lib/libnxdk.lib" "${nxdk_dir}/lib/libc++.lib" @@ -290,7 +293,7 @@ function(moonlight_prepare_nxdk nxdk_dir state_dir) if(need_prepare_libraries) message(STATUS "Preparing nxdk libraries at ${nxdk_dir}") - _moonlight_run_nxdk_make("${nxdk_dir}" "nxdk bootstrap" NXDK_ONLY=y) + _moonlight_run_nxdk_make("${nxdk_dir}" "nxdk bootstrap" NXDK_ONLY=y -j4) else() message(STATUS "Using existing nxdk library outputs from ${nxdk_dir}") endif() @@ -313,7 +316,7 @@ endfunction() # Configure the internal Xbox child build and expose it as the moonlight_xbox target. function(moonlight_add_xbox_build) set(options) - set(oneValueArgs BINARY_DIR NXDK_DIR) + set(oneValueArgs BINARY_DIR NXDK_DIR SOURCE_NXDK_DIR) cmake_parse_arguments(MOONLIGHT_XBOX "${options}" "${oneValueArgs}" "" ${ARGN}) if(NOT MOONLIGHT_XBOX_BINARY_DIR) @@ -326,7 +329,7 @@ function(moonlight_add_xbox_build) _moonlight_get_xbox_make_program(xbox_make_program) - set(toolchain_file "${MOONLIGHT_XBOX_NXDK_DIR}/share/toolchain-nxdk.cmake") + set(toolchain_file "${CMAKE_SOURCE_DIR}/cmake/nxdk-toolchain.cmake") set(driver_script "${CMAKE_SOURCE_DIR}/cmake/run-child-build.cmake") set(configure_command "${CMAKE_COMMAND}" @@ -334,6 +337,7 @@ function(moonlight_add_xbox_build) -DMOONLIGHT_CMAKE_COMMAND:FILEPATH=${CMAKE_COMMAND} -DMOONLIGHT_DESCRIPTION:STRING=Configure Xbox child build -DMOONLIGHT_NXDK_DIR:PATH=${MOONLIGHT_XBOX_NXDK_DIR} + -DMOONLIGHT_NXDK_SOURCE_DIR:PATH=${MOONLIGHT_XBOX_SOURCE_NXDK_DIR} -DMOONLIGHT_SOURCE_DIR:PATH=${CMAKE_SOURCE_DIR} -DMOONLIGHT_BINARY_DIR:PATH=${MOONLIGHT_XBOX_BINARY_DIR} -DMOONLIGHT_WORKING_DIRECTORY:PATH=${CMAKE_SOURCE_DIR} diff --git a/cmake/run-child-build.cmake b/cmake/run-child-build.cmake index 8704a4d..61c5cf8 100644 --- a/cmake/run-child-build.cmake +++ b/cmake/run-child-build.cmake @@ -15,7 +15,7 @@ endforeach() include("${CMAKE_CURRENT_LIST_DIR}/nxdk.cmake") if(MOONLIGHT_COMMAND_MODE STREQUAL "configure") - foreach(required_var MOONLIGHT_SOURCE_DIR MOONLIGHT_MAKE_PROGRAM MOONLIGHT_TOOLCHAIN_FILE) + foreach(required_var MOONLIGHT_SOURCE_DIR MOONLIGHT_NXDK_SOURCE_DIR MOONLIGHT_MAKE_PROGRAM MOONLIGHT_TOOLCHAIN_FILE) if(NOT DEFINED ${required_var} OR "${${required_var}}" STREQUAL "") message(FATAL_ERROR "${required_var} must be defined for configure mode") endif() @@ -28,8 +28,8 @@ if(MOONLIGHT_COMMAND_MODE STREQUAL "configure") -S "${MOONLIGHT_SOURCE_DIR}" -B "${MOONLIGHT_BINARY_DIR}" -DMOONLIGHT_BUILD_KIND:STRING=XBOX - -DMOONLIGHT_SKIP_NXDK_PREP:BOOL=ON - "-DNXDK_DIR:PATH=${MOONLIGHT_NXDK_DIR}" + "-DMOONLIGHT_NXDK_DIR:PATH=${MOONLIGHT_NXDK_SOURCE_DIR}" + "-DMOONLIGHT_NXDK_BUILD_DIR:PATH=${MOONLIGHT_NXDK_DIR}" -DBUILD_DOCS:BOOL=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${MOONLIGHT_TOOLCHAIN_FILE}" diff --git a/cmake/xbox-build.cmake b/cmake/xbox-build.cmake index e856806..ba1a5bd 100644 --- a/cmake/xbox-build.cmake +++ b/cmake/xbox-build.cmake @@ -13,12 +13,11 @@ set(XBOX_XBE_DIR "${CMAKE_CURRENT_BINARY_DIR}/xbe") set(XBOX_ISO_NAME "${CMAKE_PROJECT_NAME}.iso") set(XBOX_ISO "${CMAKE_CURRENT_BINARY_DIR}/${XBOX_ISO_NAME}") -moonlight_resolve_nxdk_dir(NXDK_DIR) -set(ENV{NXDK_DIR} "${NXDK_DIR}") - -if(NOT MOONLIGHT_SKIP_NXDK_PREP) - moonlight_prepare_nxdk("${NXDK_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/nxdk-bootstrap") +if(NOT EXISTS "${NXDK_DIR}/.moonlight-nxdk-copy") + message(FATAL_ERROR "Use cmake/nxdk-toolchain.cmake to build with an isolated nxdk copy") endif() +set(ENV{NXDK_DIR} "${NXDK_DIR}") +moonlight_prepare_nxdk("${NXDK_DIR}" "${NXDK_DIR}/.moonlight-bootstrap") find_package(NXDK REQUIRED) include("${CMAKE_SOURCE_DIR}/cmake/nxdk-compat.cmake") From 98c2aaa5b27f6b41cbaba47b14345c347daa640d Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Fri, 13 Nov 2026 09:28:02 -0500 Subject: [PATCH 4/4] fix(ci): satisfy CMake and shell lint checks --- CMakeLists.txt | 8 ++++---- cmake/moonlight-dependencies.cmake | 4 +++- scripts/ffmpeg-nxdk-cc.sh | 2 +- scripts/ffmpeg-nxdk-cxx.sh | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df14b45..b826792 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,11 +72,11 @@ if(BUILD_XBOX) include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/nxdk.cmake") moonlight_resolve_nxdk_dir(source_nxdk_dir) - set(nxdk_build_dir "${MOONLIGHT_NXDK_BUILD_DIR}") - moonlight_stage_nxdk("${source_nxdk_dir}" "${nxdk_build_dir}") - moonlight_prepare_nxdk("${nxdk_build_dir}" "${nxdk_build_dir}/.moonlight-bootstrap") + set(_nxdk_build_dir "${MOONLIGHT_NXDK_BUILD_DIR}") + moonlight_stage_nxdk("${source_nxdk_dir}" "${_nxdk_build_dir}") + moonlight_prepare_nxdk("${_nxdk_build_dir}" "${_nxdk_build_dir}/.moonlight-bootstrap") moonlight_add_xbox_build( - NXDK_DIR "${nxdk_build_dir}" + NXDK_DIR "${_nxdk_build_dir}" SOURCE_NXDK_DIR "${source_nxdk_dir}" BINARY_DIR "${CMAKE_BINARY_DIR}/xbox" ) diff --git a/cmake/moonlight-dependencies.cmake b/cmake/moonlight-dependencies.cmake index 2796253..7213926 100644 --- a/cmake/moonlight-dependencies.cmake +++ b/cmake/moonlight-dependencies.cmake @@ -68,7 +68,9 @@ function(_moonlight_compute_ffmpeg_signature out_var nxdk_dir ffmpeg_source_dir) file(READ "${nxdk_dir}/.moonlight-source.signature" nxdk_revision) file(SHA256 "${ffmpeg_cc_wrapper}" ffmpeg_cc_wrapper_hash) file(SHA256 "${ffmpeg_cxx_wrapper}" ffmpeg_cxx_wrapper_hash) - file(GLOB_RECURSE compat_inputs CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.h" "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.c") + file(GLOB_RECURSE compat_inputs CONFIGURE_DEPENDS + "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.h" + "${CMAKE_SOURCE_DIR}/src/_nxdk_compat/*.c") set(compat_hashes) foreach(input IN LISTS compat_inputs) file(SHA256 "${input}" input_hash) diff --git a/scripts/ffmpeg-nxdk-cc.sh b/scripts/ffmpeg-nxdk-cc.sh index 7ac6e38..8a5b994 100644 --- a/scripts/ffmpeg-nxdk-cc.sh +++ b/scripts/ffmpeg-nxdk-cc.sh @@ -3,7 +3,7 @@ set -eu unset MSYS2_ARG_CONV_EXCL -compat_dir=$(CDPATH= cd -- "$(dirname -- "$0")/../src/_nxdk_compat" && pwd) +compat_dir=$(CDPATH='' cd -- "$(dirname -- "$0")/../src/_nxdk_compat" && pwd) link=1 for arg in "$@"; do diff --git a/scripts/ffmpeg-nxdk-cxx.sh b/scripts/ffmpeg-nxdk-cxx.sh index 97e0edb..8867347 100644 --- a/scripts/ffmpeg-nxdk-cxx.sh +++ b/scripts/ffmpeg-nxdk-cxx.sh @@ -3,7 +3,7 @@ set -eu unset MSYS2_ARG_CONV_EXCL -compat_dir=$(CDPATH= cd -- "$(dirname -- "$0")/../src/_nxdk_compat" && pwd) +compat_dir=$(CDPATH='' cd -- "$(dirname -- "$0")/../src/_nxdk_compat" && pwd) link=1 for arg in "$@"; do