|
|
@ -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_STPCPY_API_MIN = 21 # stpcpy() introduced in SDK 21 |
|
|
|
ANDROID_64BIT_API_MIN = 21 # minimal API level that supports 64-bit targets |
|
|
|
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 |
|
|
|
# This class does support ONLY r10e and r19c/r20 NDK |
|
|
|
class Android: |
|
|
|
class Android: |
|
|
|
ctx = None # waf context |
|
|
|
ctx = None # waf context |
|
|
@ -348,14 +350,100 @@ class Android: |
|
|
|
ldflags += ['-march=armv5te'] |
|
|
|
ldflags += ['-march=armv5te'] |
|
|
|
return ldflags |
|
|
|
return ldflags |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NintendoSwitch: |
|
|
|
|
|
|
|
ctx = None # waf context |
|
|
|
|
|
|
|
arch = "arm64" |
|
|
|
|
|
|
|
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 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] |
|
|
|
|
|
|
|
if cxx: |
|
|
|
|
|
|
|
# while these are supported, they could fuck up the crappy dynamic linker |
|
|
|
|
|
|
|
cflags += ['-fno-exceptions', '-fno-rtti'] |
|
|
|
|
|
|
|
# the game wants GNU extensions |
|
|
|
|
|
|
|
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): |
|
|
|
|
|
|
|
# NOTE: shared libraries should be built without standard libs, so that they could import their contents from the NRO, |
|
|
|
|
|
|
|
# but executables, including the SDL2 sanity check, will generally require libstdc++ and libm, which we will add manually |
|
|
|
|
|
|
|
ldflags = [] # ['-lm', '-lstdc++'] |
|
|
|
|
|
|
|
return ldflags |
|
|
|
|
|
|
|
|
|
|
|
def options(opt): |
|
|
|
def options(opt): |
|
|
|
android = opt.add_option_group('Android options') |
|
|
|
xc = opt.add_option_group('Cross compile options') |
|
|
|
android.add_option('--android', action='store', dest='ANDROID_OPTS', default=None, |
|
|
|
xc.add_option('--android', action='store', dest='ANDROID_OPTS', default=None, |
|
|
|
help='enable building for android, format: --android=<arch>,<toolchain>,<api>, example: --android=armeabi-v7a-hard,4.9,9') |
|
|
|
help='enable building for android, format: --android=<arch>,<toolchain>,<api>, example: --android=armeabi-v7a-hard,4.9,9') |
|
|
|
|
|
|
|
xc.add_option('--enable-magx', action='store_true', dest='MAGX', default=False, |
|
|
|
magx = opt.add_option_group('MotoMAGX options') |
|
|
|
help='enable building for Motorola MAGX [default: %default]') |
|
|
|
magx.add_option('--enable-magx', action = 'store_true', dest = 'MAGX', default = False, |
|
|
|
xc.add_option('--enable-msvc-wine', action='store_true', dest='MSVC_WINE', default=False, |
|
|
|
help = 'enable targetting for MotoMAGX phones [default: %default]') |
|
|
|
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): |
|
|
|
def configure(conf): |
|
|
|
if conf.options.ANDROID_OPTS: |
|
|
|
if conf.options.ANDROID_OPTS: |
|
|
@ -389,18 +477,42 @@ def configure(conf): |
|
|
|
conf.msg('... C/C++ flags', ' '.join(android.cflags()).replace(android.ndk_home, '$NDK/')) |
|
|
|
conf.msg('... C/C++ flags', ' '.join(android.cflags()).replace(android.ndk_home, '$NDK/')) |
|
|
|
conf.msg('... link flags', ' '.join(android.linkflags()).replace(android.ndk_home, '$NDK/')) |
|
|
|
conf.msg('... link flags', ' '.join(android.linkflags()).replace(android.ndk_home, '$NDK/')) |
|
|
|
conf.msg('... ld flags', ' '.join(android.ldflags()).replace(android.ndk_home, '$NDK/')) |
|
|
|
conf.msg('... ld flags', ' '.join(android.ldflags()).replace(android.ndk_home, '$NDK/')) |
|
|
|
|
|
|
|
|
|
|
|
# conf.env.ANDROID_OPTS = android |
|
|
|
|
|
|
|
conf.env.DEST_OS2 = 'android' |
|
|
|
|
|
|
|
elif conf.options.MAGX: |
|
|
|
elif conf.options.MAGX: |
|
|
|
# useless to change toolchain path, as toolchain meant to be placed in this path |
|
|
|
# useless to change toolchain path, as toolchain meant to be placed in this path |
|
|
|
toolchain_path = '/opt/toolchains/motomagx/arm-eabi2/lib/' |
|
|
|
toolchain_path = '/opt/toolchains/motomagx/arm-eabi2/lib/' |
|
|
|
conf.env.INCLUDES_MAGX = [toolchain_path + i for i in ['ezx-z6/include', 'qt-2.3.8/include']] |
|
|
|
conf.env.INCLUDES_MAGX = [toolchain_path + i for i in ['ezx-z6/include', 'qt-2.3.8/include']] |
|
|
|
conf.env.LIBPATH_MAGX = [toolchain_path + i for i in ['ezx-z6/lib', 'qt-2.3.8/lib']] |
|
|
|
conf.env.LIBPATH_MAGX = [toolchain_path + i for i in ['ezx-z6/lib', 'qt-2.3.8/lib']] |
|
|
|
conf.env.LINKFLAGS_MAGX = ['-Wl,-rpath-link=' + i for i in conf.env.LIBPATH_MAGX] |
|
|
|
conf.env.LINKFLAGS_MAGX = ['-Wl,-rpath-link=' + i for i in conf.env.LIBPATH_MAGX] |
|
|
|
|
|
|
|
elif conf.options.MSVC_WINE: |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
toolchain_path = conf.environ['MSVC_WINE_PATH'] |
|
|
|
|
|
|
|
except KeyError: |
|
|
|
|
|
|
|
conf.fatal('Set MSVC_WINE_PATH environment variable to the MSVC toolchain root!') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
conf.environ['CC'] = conf.environ['CXX'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'cl') |
|
|
|
|
|
|
|
conf.environ['LINK_CXX'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'link') |
|
|
|
|
|
|
|
conf.environ['AR'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'lib') |
|
|
|
|
|
|
|
conf.environ['WINRC'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'rc') |
|
|
|
|
|
|
|
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.MAGX = conf.options.MAGX |
|
|
|
MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android' }) |
|
|
|
conf.env.MSVC_WINE = conf.options.MSVC_WINE |
|
|
|
|
|
|
|
MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android', '__SWITCH__' : 'nswitch' }) |
|
|
|
for k in c_config.MACRO_TO_DESTOS: |
|
|
|
for k in c_config.MACRO_TO_DESTOS: |
|
|
|
MACRO_TO_DESTOS[k] = c_config.MACRO_TO_DESTOS[k] # ordering is important |
|
|
|
MACRO_TO_DESTOS[k] = c_config.MACRO_TO_DESTOS[k] # ordering is important |
|
|
|
c_config.MACRO_TO_DESTOS = MACRO_TO_DESTOS |
|
|
|
c_config.MACRO_TO_DESTOS = MACRO_TO_DESTOS |
|
|
@ -433,11 +545,17 @@ compiler_cxx_configure = getattr(compiler_cxx, 'configure') |
|
|
|
compiler_c_configure = getattr(compiler_c, 'configure') |
|
|
|
compiler_c_configure = getattr(compiler_c, 'configure') |
|
|
|
|
|
|
|
|
|
|
|
def patch_compiler_cxx_configure(conf): |
|
|
|
def patch_compiler_cxx_configure(conf): |
|
|
|
|
|
|
|
if not conf.env.MSVC_WINE: |
|
|
|
compiler_cxx_configure(conf) |
|
|
|
compiler_cxx_configure(conf) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
conf.load('msvc', funs='no_autodetect') |
|
|
|
post_compiler_cxx_configure(conf) |
|
|
|
post_compiler_cxx_configure(conf) |
|
|
|
|
|
|
|
|
|
|
|
def patch_compiler_c_configure(conf): |
|
|
|
def patch_compiler_c_configure(conf): |
|
|
|
|
|
|
|
if not conf.env.MSVC_WINE: |
|
|
|
compiler_c_configure(conf) |
|
|
|
compiler_c_configure(conf) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
conf.load('msvc', funs='no_autodetect') |
|
|
|
post_compiler_c_configure(conf) |
|
|
|
post_compiler_c_configure(conf) |
|
|
|
|
|
|
|
|
|
|
|
setattr(compiler_cxx, 'configure', patch_compiler_cxx_configure) |
|
|
|
setattr(compiler_cxx, 'configure', patch_compiler_cxx_configure) |
|
|
|