Browse Source

Nintendo Switch support (again)

pull/2/head
fgsfds 1 year ago
parent
commit
25a1cb8ce7
  1. 1
      common/backends.h
  2. 11
      common/defaults.h
  3. 9
      common/port.h
  4. 2
      engine/common/host.c
  5. 3
      engine/common/imagelib/img_png.c
  6. 5
      engine/common/sys_con.c
  7. 21
      engine/common/system.c
  8. 2
      engine/common/whereami.c
  9. BIN
      engine/platform/nswitch/icon.jpg
  10. 140
      engine/platform/nswitch/sys_nswitch.c
  11. BIN
      engine/platform/nswitch/xash3d-fwgs.nacp
  12. 5
      engine/platform/platform.h
  13. 1
      engine/platform/posix/lib_posix.c
  14. 2
      engine/platform/posix/sys_posix.c
  15. 6
      engine/platform/sdl/sys_sdl.c
  16. 2
      engine/server/sv_game.c
  17. 63
      engine/wscript
  18. 2
      public/build.c
  19. 5
      public/build.h
  20. 3
      public/buildenums.h
  21. 4
      scripts/waifulib/compiler_optimizations.py
  22. 64
      scripts/waifulib/nswitch.py
  23. 100
      scripts/waifulib/xcompile.py
  24. 24
      wscript

1
common/backends.h

@ -47,6 +47,7 @@ GNU General Public License for more details. @@ -47,6 +47,7 @@ GNU General Public License for more details.
#define MSGBOX_SDL 1
#define MSGBOX_ANDROID 2
#define MSGBOX_WIN32 3
#define MSGBOX_NSWITCH 4
// library loading (XASH_LIB)

11
common/defaults.h

@ -47,7 +47,9 @@ SETUP BACKENDS DEFINITIONS @@ -47,7 +47,9 @@ SETUP BACKENDS DEFINITIONS
#endif // XASH_TIMER
#ifndef XASH_MESSAGEBOX
#define XASH_MESSAGEBOX MSGBOX_SDL
#if !XASH_NSWITCH // SDL2 messageboxes not available
#define XASH_MESSAGEBOX MSGBOX_SDL
#endif
#endif // XASH_MESSAGEBOX
#endif
#elif XASH_ANDROID
@ -105,6 +107,8 @@ SETUP BACKENDS DEFINITIONS @@ -105,6 +107,8 @@ SETUP BACKENDS DEFINITIONS
#ifndef XASH_MESSAGEBOX
#if XASH_WIN32
#define XASH_MESSAGEBOX MSGBOX_WIN32
#elif XASH_NSWITCH
#define XASH_MESSAGEBOX MSGBOX_NSWITCH
#else // !XASH_WIN32
#define XASH_MESSAGEBOX MSGBOX_STDERR
#endif // !XASH_WIN32
@ -177,4 +181,9 @@ Default build-depended cvar and constant values @@ -177,4 +181,9 @@ Default build-depended cvar and constant values
#define DEFAULT_FULLSCREEN 1
#endif // DEFAULT_FULLSCREEN
#if XASH_NSWITCH
#define DEFAULT_MODE_WIDTH 1280
#define DEFAULT_MODE_HEIGHT 720
#endif // XASH_NSWITCH
#endif // DEFAULTS_H

9
common/port.h

@ -39,8 +39,13 @@ GNU General Public License for more details. @@ -39,8 +39,13 @@ GNU General Public License for more details.
#if XASH_POSIX
#include <unistd.h>
#include <dlfcn.h>
#define HAVE_DUP
#ifdef XASH_NSWITCH
#define SOLDER_LIBDL_COMPAT
#include <solder.h>
#else
#include <dlfcn.h>
#define HAVE_DUP
#endif
#define O_BINARY 0
#define O_TEXT 0
#define _mkdir( x ) mkdir( x, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH )

2
engine/common/host.c

@ -1013,7 +1013,7 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha @@ -1013,7 +1013,7 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha
#if TARGET_OS_IOS
const char *IOS_GetDocsDir();
Q_strncpy( host.rootdir, IOS_GetDocsDir(), sizeof(host.rootdir) );
#elif XASH_SDL == 2
#elif (XASH_SDL == 2) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
char *szBasePath;
if( !( szBasePath = SDL_GetBasePath() ) )

3
engine/common/imagelib/img_png.c

@ -20,6 +20,9 @@ GNU General Public License for more details. @@ -20,6 +20,9 @@ GNU General Public License for more details.
#if defined(XASH_NO_NETWORK)
#include "platform/stub/net_stub.h"
#elif XASH_NSWITCH
// our ntohl is here
#include <arpa/inet.h>
#elif !XASH_WIN32
#include <netinet/in.h>
#endif

5
engine/common/sys_con.c

@ -264,6 +264,11 @@ static void Sys_PrintStdout( const char *logtime, const char *msg ) @@ -264,6 +264,11 @@ static void Sys_PrintStdout( const char *logtime, const char *msg )
void IOS_Log( const char * );
IOS_Log( buf );
#endif // TARGET_OS_IOS
#if XASH_NSWITCH && NSWITCH_DEBUG
// just spew it to stderr normally in debug mode
fprintf( stderr, "%s %s", logtime, buf );
#endif // XASH_NSWITCH && NSWITCH_DEBUG
#elif !XASH_WIN32 // Wcon does the job
Sys_PrintLogfile( STDOUT_FILENO, logtime, msg, XASH_COLORIZE_CONSOLE );
Sys_FlushStdout();

21
engine/common/system.c

@ -26,7 +26,6 @@ GNU General Public License for more details. @@ -26,7 +26,6 @@ GNU General Public License for more details.
#if XASH_POSIX
#include <unistd.h>
#include <signal.h>
#include <dlfcn.h>
#if !XASH_ANDROID
#include <pwd.h>
@ -37,6 +36,10 @@ GNU General Public License for more details. @@ -37,6 +36,10 @@ GNU General Public License for more details.
#include <process.h>
#endif
#if XASH_NSWITCH
#include <switch.h>
#endif
#include "menu_int.h" // _UPDATE_PAGE macro
#include "library.h"
@ -126,7 +129,7 @@ const char *Sys_GetCurrentUser( void ) @@ -126,7 +129,7 @@ const char *Sys_GetCurrentUser( void )
if( GetUserName( s_userName, &size ))
return s_userName;
#elif XASH_POSIX && !XASH_ANDROID
#elif XASH_POSIX && !XASH_ANDROID && !XASH_NSWITCH
uid_t uid = geteuid();
struct passwd *pw = getpwuid( uid );
@ -566,6 +569,19 @@ it explicitly doesn't use internal allocation or string copy utils @@ -566,6 +569,19 @@ it explicitly doesn't use internal allocation or string copy utils
*/
qboolean Sys_NewInstance( const char *gamedir )
{
#if XASH_NSWITCH
char newargs[4096];
const char *exe = host.argv[0]; // arg 0 is always the full NRO path
// TODO: carry over the old args (assuming you can even pass any)
Q_snprintf( newargs, sizeof( newargs ), "%s -game %s", exe, gamedir );
// just restart the entire thing
printf( "envSetNextLoad exe: `%s`\n", exe );
printf( "envSetNextLoad argv:\n`%s`\n", newargs );
Host_Shutdown( );
envSetNextLoad( exe, newargs );
exit( 0 );
#else
int i = 0;
qboolean replacedArg = false;
size_t exelen;
@ -613,6 +629,7 @@ qboolean Sys_NewInstance( const char *gamedir ) @@ -613,6 +629,7 @@ qboolean Sys_NewInstance( const char *gamedir )
free( newargs[i] );
free( newargs );
free( exe );
#endif
return false;
}

2
engine/common/whereami.c

@ -795,7 +795,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) @@ -795,7 +795,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
return length;
}
#elif defined(__sgi)
#elif defined(__sgi) || defined(__SWITCH__)
/*
* These functions are stubbed for now to get the code compiling.

BIN
engine/platform/nswitch/icon.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

140
engine/platform/nswitch/sys_nswitch.c

@ -0,0 +1,140 @@ @@ -0,0 +1,140 @@
/*
switch.c - switch backend
Copyright (C) 2021-2023 fgsfds
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "platform/platform.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <switch.h>
#include <solder.h>
#include <SDL.h>
static int nxlink_sock = -1;
/* HACKHACK: force-export stuff required by the dynamic libs */
// libunwind stuff for C++ exceptions, required by filesystem_stdio
extern void *_Unwind_GetIPInfo;
extern void *_Unwind_Resume_or_Rethrow;
extern void *_Unwind_GetRegionStart;
extern void *_Unwind_Resume;
extern void *_Unwind_DeleteException;
extern void *_Unwind_RaiseException;
extern void *_Unwind_SetIP;
extern void *_Unwind_GetTextRelBase;
extern void *_Unwind_GetLanguageSpecificData;
extern void *_Unwind_SetGR;
extern void *_Unwind_GetDataRelBase;
// these are macros in our libc, so we need to wrap them
static int tolower_fn(int c) { return tolower(c); }
static int toupper_fn(int c) { return toupper(c); }
static int isalnum_fn(int c) { return isalnum(c); }
static int isalpha_fn(int c) { return isalpha(c); }
static const solder_export_t aux_exports[] =
{
SOLDER_EXPORT("tolower", tolower_fn),
SOLDER_EXPORT("toupper", toupper_fn),
SOLDER_EXPORT("isalnum", isalnum_fn),
SOLDER_EXPORT("isalpha", isalpha_fn),
SOLDER_EXPORT_SYMBOL(mkdir),
SOLDER_EXPORT_SYMBOL(remove),
SOLDER_EXPORT_SYMBOL(rename),
SOLDER_EXPORT_SYMBOL(fsync),
SOLDER_EXPORT_SYMBOL(strchrnul),
SOLDER_EXPORT_SYMBOL(stpcpy),
SOLDER_EXPORT_SYMBOL(_Unwind_GetIPInfo),
SOLDER_EXPORT_SYMBOL(_Unwind_Resume_or_Rethrow),
SOLDER_EXPORT_SYMBOL(_Unwind_GetRegionStart),
SOLDER_EXPORT_SYMBOL(_Unwind_Resume),
SOLDER_EXPORT_SYMBOL(_Unwind_DeleteException),
SOLDER_EXPORT_SYMBOL(_Unwind_RaiseException),
SOLDER_EXPORT_SYMBOL(_Unwind_SetIP),
SOLDER_EXPORT_SYMBOL(_Unwind_GetTextRelBase),
SOLDER_EXPORT_SYMBOL(_Unwind_GetLanguageSpecificData),
SOLDER_EXPORT_SYMBOL(_Unwind_SetGR),
SOLDER_EXPORT_SYMBOL(_Unwind_GetDataRelBase),
};
const solder_export_t *__solder_aux_exports = aux_exports;
const size_t __solder_num_aux_exports = sizeof(aux_exports) / sizeof(*aux_exports);
/* end of export crap */
void Platform_ShellExecute( const char *path, const char *parms )
{
Con_Reportf( S_WARN "Tried to shell execute ;%s; -- not supported\n", path );
}
#if XASH_MESSAGEBOX == MSGBOX_NSWITCH
void Platform_MessageBox( const char *title, const char *message, qboolean unused )
{
// TODO: maybe figure out how to show an actual messagebox or an on-screen console
// without murdering the renderer
// assume this is a fatal error
FILE *f = fopen( "fatal.log", "w" );
if ( f )
{
fprintf( f, "%s:\n%s\n", title, message );
fclose( f );
}
// dump to nxlink as well
fprintf( stderr, "%s:\n%s\n", title, message );
}
#endif // XASH_MESSAGEBOX == MSGBOX_NSWITCH
// this gets executed before main(), do not delete
void userAppInit( void )
{
socketInitializeDefault( );
#ifdef NSWITCH_DEBUG
nxlink_sock = nxlinkStdio( );
#endif
if ( solder_init( 0 ) < 0 )
{
fprintf( stderr, "solder_init() failed: %s\n", solder_dlerror() );
fflush( stderr );
exit( 1 );
}
}
// this gets executed on exit(), do not delete
void userAppExit( void )
{
solder_quit( );
if ( nxlink_sock >= 0 )
{
close( nxlink_sock );
nxlink_sock = -1;
}
socketExit( );
}
void NSwitch_Init( void )
{
printf( "NSwitch_Init\n" );
}
void NSwitch_Shutdown( void )
{
printf( "NSwitch_Shutdown\n" );
// force deinit everything SDL-related to avoid issues with changing games
if ( SDL_WasInit( 0 ) )
SDL_Quit( );
}

BIN
engine/platform/nswitch/xash3d-fwgs.nacp

Binary file not shown.

5
engine/platform/platform.h

@ -51,6 +51,11 @@ void Platform_UpdateStatusLine( void ); @@ -51,6 +51,11 @@ void Platform_UpdateStatusLine( void );
static inline void Platform_UpdateStatusLine( void ) { }
#endif
#if XASH_NSWITCH
void NSwitch_Init( void );
void NSwitch_Shutdown( void );
#endif
/*
==============================================================================

1
engine/platform/posix/lib_posix.c

@ -15,7 +15,6 @@ GNU General Public License for more details. @@ -15,7 +15,6 @@ GNU General Public License for more details.
#define _GNU_SOURCE
#include "platform/platform.h"
#if XASH_LIB == LIB_POSIX
#include <dlfcn.h>
#ifdef XASH_IRIX
#include "platform/irix/dladdr.h"
#endif

2
engine/platform/posix/sys_posix.c

@ -67,7 +67,7 @@ static qboolean Sys_FindExecutable( const char *baseName, char *buf, size_t size @@ -67,7 +67,7 @@ static qboolean Sys_FindExecutable( const char *baseName, char *buf, size_t size
return false;
}
#if !XASH_ANDROID
#if !XASH_ANDROID && !XASH_NSWITCH
void Platform_ShellExecute( const char *path, const char *parms )
{
char xdgOpen[128];

6
engine/platform/sdl/sys_sdl.c

@ -68,6 +68,9 @@ void Platform_Init( void ) @@ -68,6 +68,9 @@ void Platform_Init( void )
#ifdef XASH_WIN32
Wcon_CreateConsole(); // system console used by dedicated server or show fatal errors
#endif
#ifdef XASH_NSWITCH
NSwitch_Init();
#endif
SDLash_InitCursors();
}
@ -79,4 +82,7 @@ void Platform_Shutdown( void ) @@ -79,4 +82,7 @@ void Platform_Shutdown( void )
#ifdef XASH_WIN32
Wcon_DestroyConsole();
#endif
#ifdef XASH_NSWITCH
NSwitch_Shutdown();
#endif
}

2
engine/server/sv_game.c

@ -3100,7 +3100,7 @@ void SV_SetStringArrayMode( qboolean dynamic ) @@ -3100,7 +3100,7 @@ void SV_SetStringArrayMode( qboolean dynamic )
#endif
}
#if XASH_64BIT && !XASH_WIN32 && !XASH_APPLE
#if XASH_64BIT && !XASH_WIN32 && !XASH_APPLE && !XASH_NSWITCH
#define USE_MMAP
#include <sys/mman.h>
#endif

63
engine/wscript

@ -48,6 +48,14 @@ def configure(conf): @@ -48,6 +48,14 @@ def configure(conf):
conf.options.NO_ASYNC_RESOLVE = True
if not conf.check_cc( fragment='int main(){ int i = socket();}', lib = 'wattcpwl', mandatory=False ):
conf.define('XASH_NO_NETWORK',1)
elif conf.env.DEST_OS == 'nswitch':
conf.load('sdl2')
if not conf.env.HAVE_SDL2:
conf.fatal('SDL2 not availiable! Install switch-sdl2!')
conf.define('XASH_SDL', 2)
# disallow undefined symbols
conf.env.append_unique('CXXFLAGS', '-Wl,--no-undefined')
conf.env.append_unique('CFLAGS', '-Wl,--no-undefined')
elif conf.options.FBDEV_SW:
# unused, XASH_LINUX without XASH_SDL gives fbdev & alsa support
# conf.define('XASH_FBDEV', 1)
@ -123,7 +131,7 @@ def build(bld): @@ -123,7 +131,7 @@ def build(bld):
if bld.env.DEST_OS == 'win32':
libs += ['USER32', 'SHELL32', 'GDI32', 'ADVAPI32', 'DBGHELP', 'PSAPI', 'WS2_32' ]
source += bld.path.ant_glob(['platform/win32/*.c'])
elif bld.env.DEST_OS != 'dos': #posix
elif bld.env.DEST_OS != 'dos' and bld.env.DEST_OS != 'nswitch': #posix
libs += [ 'M', 'RT', 'PTHREAD', 'ASOUND']
if not bld.env.STATIC:
libs += ['DL']
@ -162,6 +170,11 @@ def build(bld): @@ -162,6 +170,11 @@ def build(bld):
libs += ['LOG']
source += bld.path.ant_glob(['platform/android/*.cpp', 'platform/android/*.c', 'platform/linux/*.c'])
if bld.env.DEST_OS == 'nswitch':
libs += [ 'SOLDER' ]
source += bld.path.ant_glob(['platform/posix/*.c'])
source += bld.path.ant_glob(['platform/nswitch/*.c'])
# add client files
if not bld.env.DEDICATED:
source += bld.path.ant_glob([
@ -172,22 +185,34 @@ def build(bld): @@ -172,22 +185,34 @@ def build(bld):
includes = ['server', 'client', 'client/vgui' ]
if bld.env.SINGLE_BINARY:
install_path = bld.env.BINDIR
program = 'cxxprogram' if is_cxx_link else 'cprogram'
if bld.env.STATIC:
program += '_static'
features = ['c', program]
# Switch has custom parameters
if bld.env.DEST_OS == 'nswitch':
bld(source = source,
target = 'xash',
features = 'c cxxprogram',
includes = includes,
use = libs,
install_path = None,
nro_install_path = bld.env.BINDIR,
nacp = 'platform/nswitch/xash3d-fwgs.nacp',
icon = 'platform/nswitch/icon.jpg')
else:
install_path = bld.env.LIBDIR
features = ['c', 'cxxshlib' if is_cxx_link else 'cshlib']
bld(source = source,
target = 'xash',
features = features,
includes = includes,
use = libs,
install_path = install_path,
subsystem = bld.env.MSVC_SUBSYSTEM,
rpath = '$ORIGIN'
)
if bld.env.SINGLE_BINARY:
install_path = bld.env.BINDIR
program = 'cxxprogram' if is_cxx_link else 'cprogram'
if bld.env.STATIC:
program += '_static'
features = ['c', program]
else:
install_path = bld.env.LIBDIR
features = ['c', 'cxxshlib' if is_cxx_link else 'cshlib']
bld(source = source,
target = 'xash',
features = features,
includes = includes,
use = libs,
install_path = install_path,
subsystem = bld.env.MSVC_SUBSYSTEM,
rpath = '$ORIGIN'
)

2
public/build.c

@ -109,6 +109,8 @@ const char *Q_PlatformStringByID( const int platform ) @@ -109,6 +109,8 @@ const char *Q_PlatformStringByID( const int platform )
return "serenity";
case PLATFORM_IRIX:
return "irix";
case PLATFORM_NSWITCH:
return "nswitch";
}
assert( 0 );

5
public/build.h

@ -82,6 +82,7 @@ Then you can use another oneliner to query all variables: @@ -82,6 +82,7 @@ Then you can use another oneliner to query all variables:
#undef XASH_SERENITY
#undef XASH_WIN32
#undef XASH_X86
#undef XASH_NSWITCH
//================================================================
//
@ -119,12 +120,14 @@ Then you can use another oneliner to query all variables: @@ -119,12 +120,14 @@ Then you can use another oneliner to query all variables:
#if TARGET_OS_IOS
#define XASH_IOS 1
#endif // TARGET_OS_IOS
#elif defined __SWITCH__
#define XASH_NSWITCH 1
#else
#error
#endif
#endif
#if XASH_ANDROID || defined XASH_IOS
#if XASH_ANDROID || defined XASH_IOS || defined XASH_NSWITCH
#define XASH_MOBILE_PLATFORM 1
#endif

3
public/buildenums.h

@ -39,6 +39,7 @@ GNU General Public License for more details. @@ -39,6 +39,7 @@ GNU General Public License for more details.
#define PLATFORM_HAIKU 10
#define PLATFORM_SERENITY 11
#define PLATFORM_IRIX 12
#define PLATFORM_NSWITCH 13
#if XASH_WIN32
#define XASH_PLATFORM PLATFORM_WIN32
@ -64,6 +65,8 @@ GNU General Public License for more details. @@ -64,6 +65,8 @@ GNU General Public License for more details.
#define XASH_PLATFORM PLATFORM_SERENITY
#elif XASH_IRIX
#define XASH_PLATFORM PLATFORM_IRIX
#elif XASH_NSWITCH
#define XASH_PLATFORM PLATFORM_NSWITCH
#else
#error
#endif

4
scripts/waifulib/compiler_optimizations.py

@ -169,4 +169,8 @@ def get_optimization_flags(conf): @@ -169,4 +169,8 @@ def get_optimization_flags(conf):
if conf.options.POLLY:
cflags += conf.get_flags_by_compiler(POLLY_CFLAGS, conf.env.COMPILER_CC)
if conf.env.DEST_OS == 'nswitch' and conf.options.BUILD_TYPE == 'debug':
# enable remote debugger
cflags.append('-DNSWITCH_DEBUG')
return cflags, linkflags

64
scripts/waifulib/nswitch.py

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
# encoding: utf-8
# nswitch.py -- switch NRO task
# Copyright (C) 2018 a1batross
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
from waflib.Tools import ccroot
from waflib import *
def configure(conf):
conf.find_program('elf2nro')
v = conf.env
v.ELF2NRO_NACP_F = ['--nacp=']
v.ELF2NRO_ICON_F = ['--icon=']
class elf2nro(Task.Task):
color = 'RED'
run_str = '${ELF2NRO} ${ELFFILE} ${TGT} ${ELF2NRO_NACP_F?NACP}${NACP} ${ELF2NRO_ICON_F?ICON}${ICON}'
def keyword(self):
if Logs.colors_lst['USE']: # red/blue switch colors :)
return '%sConverting to NRO' % Logs.colors_lst['CYAN']
return 'Converting to NRO'
@TaskGen.feature('cxxprogram')
@TaskGen.after_method('apply_link')
def apply_nro(self):
elffile = self.link_task.outputs[0]
nodes = [elffile]
def add_source_file(ctx, nodes, f):
if f:
if isinstance(f, str):
node = ctx.path.make_node(f)
elif isinstance(f, Node.Node):
node = f
nodes += [node]
return node
return None
nacpfile = add_source_file(self, nodes, getattr(self, 'nacp', None))
iconfile = add_source_file(self, nodes, getattr(self, 'icon', None))
self.env.ELFFILE = str(elffile)
if nacpfile: self.env.NACP = str(nacpfile)
if iconfile: self.env.ICON = str(iconfile)
tsk = self.nro_task = self.create_task('elf2nro', nodes)
self.nro_task.set_outputs(nodes[0].change_ext('.nro'))
inst_to = getattr(self, 'nro_install_path', None)
if inst_to:
self.add_install_files(install_to=inst_to,
install_from=tsk.outputs[:], chmod=Utils.O755, task=tsk)

100
scripts/waifulib/xcompile.py

@ -30,6 +30,8 @@ ANDROID_NDK_API_MIN = { 10: 3, 19: 16, 20: 16, 23: 16, 25: 19 } # minimal API le @@ -30,6 +30,8 @@ ANDROID_NDK_API_MIN = { 10: 3, 19: 16, 20: 16, 23: 16, 25: 19 } # minimal API le
ANDROID_STPCPY_API_MIN = 21 # stpcpy() introduced in SDK 21
ANDROID_64BIT_API_MIN = 21 # minimal API level that supports 64-bit targets
NSWITCH_ENVVARS = ['DEVKITPRO']
# This class does support ONLY r10e and r19c/r20 NDK
class Android:
ctx = None # waf context
@ -348,6 +350,87 @@ class Android: @@ -348,6 +350,87 @@ class Android:
ldflags += ['-march=armv5te']
return ldflags
class NintendoSwitch:
ctx = None # waf context
arch = "aarch64"
dkp_dir = None
portlibs_dir = None
dka64_dir = None
libnx_dir = None
def __init__(self, ctx):
self.ctx = ctx
for i in NSWITCH_ENVVARS:
self.dkp_dir = os.getenv(i)
if self.dkp_dir != None:
break
else:
ctx.fatal('Set %s environment variable pointing to the DEVKITPRO home!' %
' or '.join(NSWITCH_ENVVARS))
self.dkp_dir = os.path.abspath(self.dkp_dir)
self.dka64_dir = os.path.join(self.dkp_dir, 'devkitA64')
if not os.path.exists(self.dka64_dir):
ctx.fatal('devkitA64 not found in `%s`. Install devkitA64!' % self.dka64_dir)
self.libnx_dir = os.path.join(self.dkp_dir, 'libnx')
if not os.path.exists(self.libnx_dir):
ctx.fatal('libnx not found in `%s`. Install libnx!' % self.libnx_dir)
self.portlibs_dir = os.path.join(self.dkp_dir, 'portlibs', 'switch')
if not os.path.exists(self.portlibs_dir):
ctx.fatal('No Switch libraries found in `%s`!' % self.portlibs_dir)
def gen_toolchain_prefix(self):
return 'aarch64-none-elf-'
def gen_gcc_toolchain_path(self):
return os.path.join(self.dka64_dir, 'bin', self.gen_toolchain_prefix())
def cc(self):
return self.gen_gcc_toolchain_path() + 'gcc'
def cxx(self):
return self.gen_gcc_toolchain_path() + 'g++'
def strip(self):
return self.gen_gcc_toolchain_path() + 'strip'
def pkgconfig(self):
# counter-intuitively, this motherfucker is in $DEVKITPRO/portlibs/switch/bin
return os.path.join(self.portlibs_dir, 'bin', self.gen_toolchain_prefix() + 'pkg-config')
def cflags(self, cxx = False):
cflags = []
# arch flags
cflags += ['-D__SWITCH__', '-march=armv8-a+crc+crypto', '-mtune=cortex-a57', '-mtp=soft', '-ftls-model=local-exec', '-fPIE']
# help the linker out
cflags += ['-ffunction-sections', '-fdata-sections']
# base include dirs
cflags += ['-isystem %s/include' % self.libnx_dir, '-I%s/include' % self.portlibs_dir]
# the game wants GNU extensions
if cxx:
cflags += ['-std=gnu++17', '-D_GNU_SOURCE']
else:
cflags += ['-std=gnu11', '-D_GNU_SOURCE']
return cflags
# they go before object list
def linkflags(self):
linkflags = ['-fPIE', '-specs=%s/switch.specs' % self.libnx_dir]
# libsolder only supports sysv hashes and we need to build everything with -rdynamic
linkflags += ['-Wl,--hash-style=sysv', '-rdynamic']
# avoid pulling in and exposing mesa's internals, that crashes it for some god forsaken reason
linkflags += ['-Wl,--exclude-libs=libglapi.a', '-Wl,--exclude-libs=libdrm_nouveau.a']
return linkflags
def ldflags(self):
# system libraries implicitly require math and C++ standard library
ldflags = ['-lm', '-lstdc++']
return ldflags
def options(opt):
xc = opt.add_option_group('Cross compile options')
xc.add_option('--android', action='store', dest='ANDROID_OPTS', default=None,
@ -356,6 +439,8 @@ def options(opt): @@ -356,6 +439,8 @@ def options(opt):
help='enable building for Motorola MAGX [default: %default]')
xc.add_option('--enable-msvc-wine', action='store_true', dest='MSVC_WINE', default=False,
help='enable building with MSVC using Wine [default: %default]')
xc.add_option('--nswitch', action='store_true', dest='NSWITCH', default = False,
help ='enable building for Nintendo Switch [default: %default]')
def configure(conf):
if conf.options.ANDROID_OPTS:
@ -408,10 +493,23 @@ def configure(conf): @@ -408,10 +493,23 @@ def configure(conf):
conf.env.DEST_OS = 'win32'
conf.env.DEST_CPU = conf.env.MSVC_TARGETS[0]
conf.env.COMPILER_CXX = conf.env.COMPILER_CC = 'msvc'
elif conf.options.NSWITCH:
conf.nswitch = nswitch = NintendoSwitch(conf)
conf.environ['CC'] = nswitch.cc()
conf.environ['CXX'] = nswitch.cxx()
conf.environ['STRIP'] = nswitch.strip()
conf.env.PKGCONFIG = nswitch.pkgconfig()
conf.env.CFLAGS += nswitch.cflags()
conf.env.CXXFLAGS += nswitch.cflags(True)
conf.env.LINKFLAGS += nswitch.linkflags()
conf.env.LDFLAGS += nswitch.ldflags()
conf.env.HAVE_M = True
conf.env.LIB_M = ['m']
conf.env.DEST_OS = 'nswitch'
conf.env.MAGX = conf.options.MAGX
conf.env.MSVC_WINE = conf.options.MSVC_WINE
MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android' })
MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android', '__SWITCH__' : 'nswitch' })
for k in c_config.MACRO_TO_DESTOS:
MACRO_TO_DESTOS[k] = c_config.MACRO_TO_DESTOS[k] # ordering is important
c_config.MACRO_TO_DESTOS = MACRO_TO_DESTOS

24
wscript

@ -132,6 +132,9 @@ def configure(conf): @@ -132,6 +132,9 @@ def configure(conf):
# Load compilers early
conf.load('xshlib xcompile compiler_c compiler_cxx')
if conf.options.NSWITCH:
conf.load('nswitch')
# HACKHACK: override msvc DEST_CPU value by something that we understand
if conf.env.DEST_CPU == 'amd64':
conf.env.DEST_CPU = 'x86_64'
@ -170,6 +173,12 @@ def configure(conf): @@ -170,6 +173,12 @@ def configure(conf):
enforce_pic = False
elif conf.env.DEST_OS == 'dos':
conf.options.SINGLE_BINARY = True
elif conf.env.DEST_OS == 'nswitch':
conf.options.NO_VGUI = True
conf.options.GL = True
conf.options.SINGLE_BINARY = True
conf.options.NO_ASYNC_RESOLVE = True
conf.options.USE_STBTT = True
if conf.env.STATIC_LINKING:
enforce_pic = False # PIC may break full static builds
@ -233,6 +242,14 @@ def configure(conf): @@ -233,6 +242,14 @@ def configure(conf):
cflags, linkflags = conf.get_optimization_flags()
# on the Switch, allow undefined symbols by default, which is needed for libsolder to work
# we'll specifically disallow for the engine executable
# additionally, shared libs are linked without libc
if conf.env.DEST_OS == 'nswitch':
linkflags.remove('-Wl,--no-undefined')
conf.env.append_unique('LINKFLAGS_cshlib', ['-nostdlib', '-nostartfiles'])
conf.env.append_unique('LINKFLAGS_cxxshlib', ['-nostdlib', '-nostartfiles'])
# And here C++ flags starts to be treated separately
cxxflags = list(cflags)
if conf.env.COMPILER_CC != 'msvc' and not conf.options.DISABLE_WERROR:
@ -282,7 +299,10 @@ def configure(conf): @@ -282,7 +299,10 @@ def configure(conf):
conf.define('ALLOCA_H', 'malloc.h')
if conf.env.DEST_OS != 'win32':
conf.check_cc(lib='dl', mandatory=False)
if conf.env.DEST_OS == 'nswitch':
conf.check_cfg(package='solder', args='--cflags --libs', uselib_store='SOLDER')
else:
conf.check_cc(lib='dl', mandatory=False)
if not conf.env.LIB_M: # HACK: already added in xcompile!
conf.check_cc(lib='m')
@ -354,7 +374,7 @@ int main(int argc, char **argv) { strchrnul(argv[1], 'x'); return 0; }''' @@ -354,7 +374,7 @@ int main(int argc, char **argv) { strchrnul(argv[1], 'x'); return 0; }'''
conf.env.LIBDIR = conf.env.BINDIR = conf.env.LIBDIR + '/xash3d'
conf.env.SHAREDIR = '${PREFIX}/share/xash3d'
else:
if sys.platform != 'win32' and not conf.env.DEST_OS == 'android':
if sys.platform != 'win32' and conf.env.DEST_OS != 'android':
conf.env.PREFIX = '/'
conf.env.SHAREDIR = conf.env.LIBDIR = conf.env.BINDIR = conf.env.PREFIX

Loading…
Cancel
Save