Add Nintendo Switch (libnx) Horizon RetroArch support.

Teach the Makefile and GitLab CI to produce a static libnx core, and adjust
threading/file I/O for newlib so the core links into a working Switch NRO.
This commit is contained in:
Ryan Rubis committed 2026-08-13 14:10:44 +08:00
1 parent d6187e5337
commit 6ed7f9bf41
6 files changed
+67 -6

No files matched your search

+8
View File
@@ -1,4 +1,12 @@
*.o
*.a
*.so
*.dll
*.dylib
*.bc
*.nro
*.elf
*.nso
*.nacp
*.pfs0
dist/
+12
View File
@@ -38,6 +38,11 @@ include:
- project: 'libretro-infrastructure/ci-templates'
file: '/android-jni.yml'
################################## CONSOLES ################################
# Nintendo Switch (libnx / Horizon)
- project: 'libretro-infrastructure/ci-templates'
file: '/libnx-static.yml'
#################################### MISC ##################################
# webOS 32-bit (LGTV)
- project: 'libretro-infrastructure/ci-templates'
@@ -109,6 +114,13 @@ android-x86:
- .libretro-android-jni-x86
- .core-defs
################################### CONSOLES #################################
# Nintendo Switch (libnx / Horizon)
libretro-build-libnx-aarch64:
extends:
- .libretro-libnx-static-retroarch-master
- .core-defs
#################################### MISC ####################################
# webOS 32-bit
libretro-build-webos-armv7a:
+11
View File
@@ -187,6 +187,17 @@ else ifeq ($(platform), wii)
EXTRA_INCLUDES := -I$(DEVKITPRO)/libogc/include
STATIC_LINKING = 1
# Nintendo Switch (libnx / Horizon)
else ifeq ($(platform), libnx)
export DEPSDIR := $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules
TARGET := $(TARGET_NAME)_libretro_$(platform).a
ENDIANNESS_DEFINES := -DLSB_FIRST -DSWITCH=1 -D__SWITCH__ -DHAVE_LIBNX -U__linux__ -U__linux
EXTRA_INCLUDES := -I$(LIBNX)/include/
FLAGS += -fPIE -ffunction-sections -fdata-sections -ftls-model=local-exec
FLAGS += -march=armv8-a -mtune=cortex-a57 -mtp=soft -mcpu=cortex-a57+crc+fp+simd
STATIC_LINKING = 1
else ifneq (,$(findstring rpi,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
+4
View File
@@ -38,6 +38,10 @@
#include <sys/mman.h>
#endif
#ifndef SSIZE_MAX
#define SSIZE_MAX ((ssize_t)(((size_t)-1) >> 1))
#endif
namespace Mednafen
{
+5 -2
View File
@@ -3,9 +3,12 @@
#define MDFN_SNES_FAUST_SPC700_IPL_HLE 1
#define MDFN_SNES_FAUST_SKETCHYSPC700OPT 1
//#define MDFN_SNES_FAUST_SKETCHYPPUOPT 1
#define HAVE_SEM_TIMEDWAIT 1
#if !defined(ANDROID) && !defined(__APPLE__)
#if !defined(__SWITCH__) && !defined(HAVE_LIBNX)
#define HAVE_SEM_TIMEDWAIT 1
#endif
#if !defined(ANDROID) && !defined(__APPLE__) && !defined(__SWITCH__) && !defined(HAVE_LIBNX)
#define PTHREAD_AFFINITY_NP cpu_set_t
#endif
+27 -4
View File
@@ -31,6 +31,9 @@
//
#if defined(__ANDROID__)
#define MDFN_USE_COND_TIMEDWAIT_MONOTONIC_NP
#elif defined(__SWITCH__) || defined(HAVE_LIBNX)
/* libnx pthread lacks a reliable CLOCK_MONOTONIC cond clock; use realtime. */
#define MDFN_USE_COND_TIMEDWAIT_REALTIME
#elif (!defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)) || defined(__APPLE__)
#define MDFN_USE_COND_TIMEDWAIT_RELATIVE_NP
#endif
@@ -256,12 +259,12 @@ uint64 Thread_SetAffinity(Thread* thread, const uint64 mask)
}
#else
#warning "Compiling without affinity setting support."
uint64 Thread_SetAffinity(Thread* thread, uint64 mask)
{
assert(mask != 0);
//
throw MDFN_Error(0, _("Setting affinity to 0x%016llx failed: %s"), (unsigned long long)mask, _("pthread_setaffinity_np() not available."));
// Affinity control is unavailable (e.g. Switch/libnx); leave scheduling alone.
(void)thread;
return 0;
}
#endif
@@ -365,7 +368,7 @@ static void CreateCond(Cond* ret)
throw MDFN_Error(ene.Errno(), _("%s failed: %s"), "pthread_condattr_init()", ene.StrError());
}
#if !defined(MDFN_USE_COND_TIMEDWAIT_RELATIVE_NP)
#if !defined(MDFN_USE_COND_TIMEDWAIT_RELATIVE_NP) && !defined(MDFN_USE_COND_TIMEDWAIT_REALTIME)
if((ptec = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)))
{
ErrnoHolder ene(ptec);
@@ -452,6 +455,26 @@ bool Cond_TimedWait(Cond* cond, Mutex* mutex, unsigned ms)
return true;
}
#elif defined(MDFN_USE_COND_TIMEDWAIT_REALTIME)
bool Cond_TimedWait(Cond* cond, Mutex* mutex, unsigned ms)
{
struct timespec abstime;
memset(&abstime, 0, sizeof(abstime));
if(clock_gettime(CLOCK_REALTIME, &abstime))
return false;
TimeSpec_AddNanoseconds(&abstime, (uint64)ms * 1000 * 1000);
int ctw_rv = pthread_cond_timedwait(&cond->c, &mutex->m, &abstime);
if(ctw_rv == ETIMEDOUT)
return false;
else if(ctw_rv)
return false;
return true;
}
#elif !defined(MDFN_USE_COND_TIMEDWAIT_RELATIVE_NP)
bool Cond_TimedWait(Cond* cond, Mutex* mutex, unsigned ms)
{