From 5306525029299ed4d234c1a1bd60493142d067f7 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Thu, 20 Sep 2018 10:47:48 -0700 Subject: [PATCH] Initial Switch support (Needs testing) --- CMakeLists.txt | 8 +- cmake/Platform/Switch.cmake | 3 + cmake/SwitchTools_nx.cmake | 174 ++++++++++++++++++++++++++++ cmake/SwitchTools_trn.cmake | 71 ++++++++++++ include/athena/Global.hpp | 2 +- include/athena/SpriteFileReader.hpp | 3 + include/athena/WiiFile.hpp | 1 + include/athena/WiiSave.hpp | 1 + include/gekko_support.h | 7 +- libnx.cmake | 51 ++++++++ src/aes.cpp | 2 +- src/athena/FileWriterNix.cpp | 2 +- src/athena/SkywardSwordQuest.cpp | 1 + src/athena/WiiFile.cpp | 1 + src/gekko_support.c | 2 +- 15 files changed, 320 insertions(+), 9 deletions(-) create mode 100644 cmake/Platform/Switch.cmake create mode 100644 cmake/SwitchTools_nx.cmake create mode 100644 cmake/SwitchTools_trn.cmake create mode 100644 libnx.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f255066..4ec01bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,9 +29,9 @@ list(APPEND CORE_EXTRA src/win32_largefilewrapper.c include/win32_largefilewrapp src/athena/FileWriterWin32.cpp src/athena/FileReaderWin32.cpp) else() list(APPEND CORE_EXTRA src/athena/FileWriterNix.cpp src/athena/FileReader.cpp) -if(APPLE OR GEKKO OR ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") +if(APPLE OR GEKKO OR NX OR ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") list(APPEND CORE_EXTRA src/osx_largefilewrapper.c include/osx_largefilewrapper.h) -if(GEKKO) +if(GEKKO OR NX) list(APPEND CORE_EXTRA src/gekko_support.c include/gekko_support.h) endif() endif() @@ -130,7 +130,7 @@ add_library(athena-wiisave EXCLUDE_FROM_ALL include/md5.h include/sha1.h ) -if(NOT MSVC AND NOT GEKKO) +if(NOT MSVC AND NOT GEKKO AND NOT NX) set_source_files_properties(src/aes.cpp PROPERTIES COMPILE_FLAGS -maes) endif() @@ -243,7 +243,7 @@ install(EXPORT AthenaTargets DESTINATION ${INSTALL_CMAKE_DIR} COMPONENT athena) # atdna import # ################ -if(NOT GEKKO) +if(NOT GEKKO AND NOT NX) add_subdirectory(atdna) # Test target atdna(atdna_test.cpp atdna/test.hpp) diff --git a/cmake/Platform/Switch.cmake b/cmake/Platform/Switch.cmake new file mode 100644 index 0000000..26ee374 --- /dev/null +++ b/cmake/Platform/Switch.cmake @@ -0,0 +1,3 @@ +set(CMAKE_EXECUTABLE_SUFFIX ".nro.so") +SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) +set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "/usr/bin/llvm-mc ${AS_FLAGS} -o ") diff --git a/cmake/SwitchTools_nx.cmake b/cmake/SwitchTools_nx.cmake new file mode 100644 index 0000000..030b20b --- /dev/null +++ b/cmake/SwitchTools_nx.cmake @@ -0,0 +1,174 @@ + +get_filename_component(__tools_switch_sdir ${CMAKE_CURRENT_LIST_FILE} PATH) # Used to locate files to be used with configure_file + +############# +## ELF2NRO ## +############# +if (NOT ELF2NRO) + # message(STATUS "Looking for makerom...") + find_program(ELF2NRO elf2nro ${DEVKITPRO}/tools/bin) + if (ELF2NRO) + message(STATUS "elf2nro: ${ELF2NRO} - found") + else () + message(WARNING "elf2nro - not found") + endif () +endif () + +############# +## ELF2KIP ## +############# +if (NOT ELF2KIP) + # message(STATUS "Looking for makerom...") + find_program(ELF2KIP elf2kip ${DEVKITPRO}/tools/bin) + if (ELF2KIP) + message(STATUS "elf2kip: ${ELF2KIP} - found") + else () + message(WARNING "elf2kip - not found") + endif () +endif () +############# +## ELF2NSO ## +############# +if (NOT ELF2NSO) + # message(STATUS "Looking for makerom...") + find_program(ELF2NSO elf2nso ${DEVKITPRO}/tools/bin) + if (ELF2NSO) + message(STATUS "elf2nso: ${ELF2NSO} - found") + else () + message(WARNING "elf2nso - not found") + endif () +endif () + +############# +## BIN2S ## +############# +if (NOT BIN2S) + # message(STATUS "Looking for bin2s...") + find_program(BIN2S bin2s ${DEVKITPRO}/tools/bin) + if (BIN2S) + message(STATUS "bin2s: ${BIN2S} - found") + else () + message(WARNING "bin2s - not found") + endif () +endif () + +############# +## RAW2C ## +############# +if (NOT RAW2C) + # message(STATUS "Looking for bin2s...") + find_program(RAW2C raw2c ${DEVKITPRO}/tools/bin) + if (RAW2C) + message(STATUS "raw2c: ${RAW2C} - found") + else () + message(WARNING "raw2c - not found") + endif () +endif () + +################## +## BUILD_PFS0 ## +################## +if (NOT BUILD_PFS0) + # message(STATUS "Looking for bin2s...") + find_program(BUILD_PFS0 build_pfs0 ${DEVKITPRO}/tools/bin) + if (BUILD_PFS0) + message(STATUS "build_pfs0: ${BUILD_PFS0} - found") + else () + message(WARNING "build_pfs0 - not found") + endif () +endif () + +################ +## NACPTOOL ## +################ +if (NOT NACPTOOL) + # message(STATUS "Looking for bin2s...") + find_program(NACPTOOL nacptool ${DEVKITPRO}/tools/bin) + if (NACPTOOL) + message(STATUS "nacptool: ${NACPTOOL} - found") + else () + message(WARNING "nacptool - not found") + endif () +endif () + + +function(__add_nacp target APP_TITLE APP_AUTHOR APP_VERSION) + set(__NACP_COMMAND ${NACPTOOL} --create ${APP_TITLE} ${APP_AUTHOR} ${APP_VERSION} ${CMAKE_CURRENT_BINARY_DIR}/${target}) + + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target} + COMMAND ${__NACP_COMMAND} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + VERBATIM + ) +endfunction() +function(add_nro_target target) + get_filename_component(target_we ${target} NAME_WE) + if ((NOT (${ARGC} GREATER 1 AND "${ARGV1}" STREQUAL "NO_NACP")) OR (${ARGC} GREATER 3)) + if (${ARGC} GREATER 3) + set(APP_TITLE ${ARGV1}) + set(APP_AUTHOR ${ARGV2}) + set(APP_VERSION ${ARGV3}) + endif () + if (${ARGC} EQUAL 5) + set(APP_ICON ${ARGV4}) + endif () + if (NOT APP_TITLE) + set(APP_TITLE ${target}) + endif () + if (NOT APP_AUTHOR) + set(APP_AUTHOR "Unspecified Author") + endif () + if (NOT APP_VERSION) + set(APP_VERSION "1.0") + endif () + if (NOT APP_ICON) + if (EXISTS ${target}.png) + set(APP_ICON ${target}.png) + elseif (EXISTS icon.png) + set(APP_ICON icon.png) + elseif (NX) + set(APP_ICON ${DEVKITPRO}/libnx/default_icon.png) + else () + message(FATAL_ERROR "No icon found ! Please use NO_SMDH or provide some icon.") + endif () + endif () + if (NOT ${target_we}.nacp) + __add_nacp(${target_we}.nacp ${APP_TITLE} ${APP_AUTHOR} ${APP_VERSION}) + endif () + if (CMAKE_RUNTIME_OUTPUT_DIRECTORY) + add_custom_command(OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro + COMMAND ${ELF2NRO} $ --icon=${APP_ICON} --nacp=${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro + DEPENDS ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp + VERBATIM + ) + else () + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro + COMMAND ${ELF2NRO} $ --icon=${APP_ICON} --nacp=${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro + DEPENDS ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp + VERBATIM + ) + endif () + else () + message(STATUS "No nacp file will be generated") + if (CMAKE_RUNTIME_OUTPUT_DIRECTORY) + add_custom_command(OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro + COMMAND ${ELF2NRO} $ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro + DEPENDS ${target} + VERBATIM + ) + else () + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro + COMMAND ${ELF2NRO} $ ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro + DEPENDS ${target} + VERBATIM + ) + endif () + + endif () + if (CMAKE_RUNTIME_OUTPUT_DIRECTORY) + add_custom_target(${target_we}_nro ALL SOURCES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro) + + else () + add_custom_target(${target_we}_nro ALL SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro) + endif () +endfunction() diff --git a/cmake/SwitchTools_trn.cmake b/cmake/SwitchTools_trn.cmake new file mode 100644 index 0000000..5433757 --- /dev/null +++ b/cmake/SwitchTools_trn.cmake @@ -0,0 +1,71 @@ +set(Python_ADDITIONAL_VERSIONS 3.4 3.5 3.6) +find_package(PythonInterp 3 REQUIRED) + +set(CONVERTER "${LIBTRN}/tools/elf2nxo.py") + +function(add_nro_target target) + get_filename_component(target_we ${target} NAME_WE) + if ((NOT (${ARGC} GREATER 1 AND "${ARGV1}" STREQUAL "NO_HDR")) OR (${ARGC} GREATER 3)) + if (${ARGC} GREATER 3) + set(APP_TITLE ${ARGV1}) + set(APP_AUTHOR ${ARGV2}) + set(APP_VERSION ${ARGV3}) + endif () + if (${ARGC} EQUAL 5) + set(APP_ICON ${ARGV4}) + endif () + if (NOT APP_TITLE) + set(APP_TITLE ${target}) + endif () + if (NOT APP_AUTHOR) + set(APP_AUTHOR "Unspecified Author") + endif () + if (NOT APP_VERSION) + set(APP_VERSION "1.0") + endif () + if (NOT APP_ICON) + if (EXISTS ${target}.png) + set(APP_ICON ${target}.png) + elseif (EXISTS icon.png) + set(APP_ICON icon.png) + else () + message(FATAL_ERROR "No icon found ! Please use NO_SMDH or provide some icon.") + endif () + endif () + if (CMAKE_RUNTIME_OUTPUT_DIRECTORY) + add_custom_command(OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro + COMMAND ${PYTHON_EXECUTABLE} ${CONVERTER} -n ${APP_TITLE} -d ${APP_AUTHOR} -v ${APP_VERSION} -i ${APP_ICON} $ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro nro + DEPENDS ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp + VERBATIM + ) + else () + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro + COMMAND ${PYTHON_EXECUTABLE} ${CONVERTER} -n ${APP_TITLE} -d ${APP_AUTHOR} -v ${APP_VERSION} -i ${APP_ICON} $ ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro nro + DEPENDS ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nacp + VERBATIM + ) + endif () + else () + message(STATUS "No header will be generated") + if (CMAKE_RUNTIME_OUTPUT_DIRECTORY) + add_custom_command(OUTPUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro + COMMAND ${PYTHON_EXECUTABLE} ${CONVERTER} $ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro nro + DEPENDS ${target} + VERBATIM + ) + else () + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro + COMMAND ${PYTHON_EXECUTABLE} ${CONVERTER} $ ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro nro + DEPENDS ${target} + VERBATIM + ) + endif () + + endif () + if (CMAKE_RUNTIME_OUTPUT_DIRECTORY) + add_custom_target(${target_we}_nro ALL SOURCES ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${target_we}.nro) + + else () + add_custom_target(${target_we}_nro ALL SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${target_we}.nro) + endif () +endfunction() diff --git a/include/athena/Global.hpp b/include/athena/Global.hpp index 18bd991..e23962e 100644 --- a/include/athena/Global.hpp +++ b/include/athena/Global.hpp @@ -52,7 +52,7 @@ #endif // clang-format on -#ifdef GEKKO +#if defined(GEKKO) || defined(__SWITCH__) #include "gekko_support.h" typedef struct stat atStat64_t; #define atStat64 stat diff --git a/include/athena/SpriteFileReader.hpp b/include/athena/SpriteFileReader.hpp index 627a5c6..7f3a28a 100644 --- a/include/athena/SpriteFileReader.hpp +++ b/include/athena/SpriteFileReader.hpp @@ -8,6 +8,8 @@ namespace athena::Sakura class SpriteFile; } // Sakura +namespace athena +{ namespace io { @@ -19,6 +21,7 @@ public: Sakura::SpriteFile* readFile(); }; +} } // zelda diff --git a/include/athena/WiiFile.hpp b/include/athena/WiiFile.hpp index bfaba32..a7dcf03 100644 --- a/include/athena/WiiFile.hpp +++ b/include/athena/WiiFile.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "athena/Global.hpp" namespace athena diff --git a/include/athena/WiiSave.hpp b/include/athena/WiiSave.hpp index a6dfcf2..fa0183a 100644 --- a/include/athena/WiiSave.hpp +++ b/include/athena/WiiSave.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "athena/Global.hpp" namespace athena diff --git a/include/gekko_support.h b/include/gekko_support.h index 05082e2..9c4840d 100644 --- a/include/gekko_support.h +++ b/include/gekko_support.h @@ -1,7 +1,7 @@ #ifndef GEKKO_SUPPORT_H #define GEKKO_SUPPORT_H -#ifdef GEKKO +#if defined(GEKKO) || defined(__SWITCH__) #include #include #include @@ -11,6 +11,11 @@ #ifdef __cplusplus extern "C" { #endif +#ifdef __SWITCH__ +#define ftello64 ftello +#define fseeko64 fseeko +#endif + char * realpath(const char *path, char *resolved); int diff --git a/libnx.cmake b/libnx.cmake new file mode 100644 index 0000000..1a7b688 --- /dev/null +++ b/libnx.cmake @@ -0,0 +1,51 @@ +set(CMAKE_SYSTEM_NAME "Switch") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_C_STANDARD 11) +set(WITH_PORTLIBS ON CACHE BOOL "use portlibs ?") + +macro(msys_to_cmake_path MsysPath ResultingPath) + if(WIN32) + string(REGEX REPLACE "^/([a-zA-Z])/" "\\1:/" ${ResultingPath} "${MsysPath}") + else() + set(${ResultingPath} "${MsysPath}") + endif() +endmacro() + +msys_to_cmake_path("$ENV{DEVKITPRO}" DEVKITPRO) + +set(NX 1) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +include(SwitchTools_nx) + +if(WIN32) + set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc.exe") + set(CMAKE_CXX_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++.exe") + set(CMAKE_AR "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ar.exe" CACHE STRING "") + set(CMAKE_RANLIB "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ranlib.exe" CACHE STRING "") +else() + set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc") + set(CMAKE_CXX_COMPILER "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++") + set(CMAKE_AR "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ar" CACHE STRING "") + set(CMAKE_RANLIB "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc-ranlib" CACHE STRING "") +endif() + +set(PKG_CONFIG "${DEVKITPRO}/portlibs/bin/aarch64-none-elf-pkg-config" CACHE STRING "") +set(CPPFLAGS "-D__SWITCH__ -D__USE_LARGEFILE64=1 -D__USE_LARGEOFFSET64=1 -I${DEVKITPRO}/libnx/include -I${DEVKITPRO}/portlibs/switch/include") +set(CMAKE_C_FLAGS "${CPPFLAGS} -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIC -ffunction-sections" CACHE STRING "C flags") +set(CMAKE_CXX_FLAGS "${CPPFLAGS} ${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -std=gnu++11" CACHE STRING "C++ flags") + +if(WITH_PORTLIBS) + set(CMAKE_FIND_ROOT_PATH ${DEVKITPRO}/devkitA64 ${DEVKITPRO} ${DEVKITPRO}/libnx ${DEVKITPRO}/portlibs/switch) +else() + set(CMAKE_FIND_ROOT_PATH ${DEVKITPRO}/devkitA64 ${DEVKITPRO}/libnx ${DEVKITPRO}) +endif() + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +#set(CMAKE_STATIC_LINKER_FLAGS_INIT "-march=armv8-a -mtune=cortex-a57 -mtp=soft -L${DEVKITPRO}/libnx/lib -L${DEVKITPRO}/portlibs/switch/lib") +set(CMAKE_EXE_LINKER_FLAGS_INIT "-specs=${DEVKITPRO}/libnx/switch.specs -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -L${DEVKITPRO}/libnx/lib -L${DEVKITPRO}/portlibs/switch/lib") + +set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available") +set(CMAKE_INSTALL_PREFIX ${DEVKITPRO}/portlibs/switch) diff --git a/src/aes.cpp b/src/aes.cpp index 998e623..3abc4dc 100644 --- a/src/aes.cpp +++ b/src/aes.cpp @@ -3,7 +3,7 @@ #include #if _WIN32 #include -#elif !GEKKO +#elif !defined(GEKKO) && !defined(__SWITCH__) #include #endif diff --git a/src/athena/FileWriterNix.cpp b/src/athena/FileWriterNix.cpp index 9aa618b..072dbc5 100644 --- a/src/athena/FileWriterNix.cpp +++ b/src/athena/FileWriterNix.cpp @@ -2,7 +2,7 @@ #if __APPLE__ || __FreeBSD__ #include "osx_largefilewrapper.h" -#elif GEKKO +#elif GEKKO || __SWITCH__ #include "gekko_support.h" #include "osx_largefilewrapper.h" #endif diff --git a/src/athena/SkywardSwordQuest.cpp b/src/athena/SkywardSwordQuest.cpp index 0c032d1..ab60b4b 100644 --- a/src/athena/SkywardSwordQuest.cpp +++ b/src/athena/SkywardSwordQuest.cpp @@ -1,5 +1,6 @@ #include "athena/SkywardSwordQuest.hpp" #include "athena/Checksums.hpp" +#include "athena/Utility.hpp" #include "utf8proc.h" #include diff --git a/src/athena/WiiFile.cpp b/src/athena/WiiFile.cpp index ce80199..ce9d379 100644 --- a/src/athena/WiiFile.cpp +++ b/src/athena/WiiFile.cpp @@ -1,4 +1,5 @@ #include "athena/WiiFile.hpp" +#include "athena/Utility.hpp" #include namespace athena diff --git a/src/gekko_support.c b/src/gekko_support.c index aaf20e6..dd06203 100644 --- a/src/gekko_support.c +++ b/src/gekko_support.c @@ -1,4 +1,4 @@ -#if defined(GEKKO) +#if defined(GEKKO) || defined(__SWITCH__) #include "gekko_support.h" #define SYMLOOP_MAX 8 #include