diff --git a/.gitignore b/.gitignore index da528b0..36a1be8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Build directory build/ +build-win64/ # Documentation drafts doc/ diff --git a/CMakeLists.txt b/CMakeLists.txt index cf53515..7771c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ endif() if(NOT FXLINK_DISABLE_SDL2) pkg_check_modules(sdl2 REQUIRED sdl2 IMPORTED_TARGET) endif() -pkg_check_modules(ncurses REQUIRED ncurses IMPORTED_TARGET) +pkg_check_modules(ncurses REQUIRED ncursesw IMPORTED_TARGET) set(CMAKE_INSTALL_MESSAGE LAZY) set(SRC "${CMAKE_CURRENT_SOURCE_DIR}") @@ -30,8 +30,13 @@ target_include_directories(fxgxa PUBLIC fxgxa/) target_link_libraries(fxgxa PkgConfig::libpng) # fxg1a as a symlink (for compatibility) -add_custom_target(fxg1a ALL - COMMAND ${CMAKE_COMMAND} -E create_symlink "fxgxa" "fxg1a") +if(WIN32) + add_custom_target(fxg1a ALL + COMMAND ${CMAKE_COMMAND} -E create_symlink "fxgxa.exe" "fxg1a.exe") +else() + add_custom_target(fxg1a ALL + COMMAND ${CMAKE_COMMAND} -E create_symlink "fxgxa" "fxg1a") +endif() # fxsdk add_custom_command(OUTPUT "${BIN}/fxsdk.sh" @@ -86,10 +91,12 @@ if(NOT FXLINK_DISABLE_SDL2) endif() # fxsdk-gdb-bridge -add_executable(fxsdk-gdb-bridge fxsdk/gdb-bridge.c) -target_link_libraries(fxsdk-gdb-bridge libfxlink) -target_include_directories(fxsdk-gdb-bridge PRIVATE - "${SRC}/fxlink/include") +if(NOT WIN32) + add_executable(fxsdk-gdb-bridge fxsdk/gdb-bridge.c) + target_link_libraries(fxsdk-gdb-bridge libfxlink) + target_include_directories(fxsdk-gdb-bridge PRIVATE + "${SRC}/fxlink/include") +endif() # Install rules @@ -98,7 +105,9 @@ install(PROGRAMS "${BIN}/fxsdk.sh" TYPE BIN RENAME fxsdk) install(DIRECTORY fxsdk/assets DESTINATION share/fxsdk) install(DIRECTORY fxsdk/scripts DESTINATION share/fxsdk USE_SOURCE_PERMISSIONS) install(DIRECTORY fxsdk/cmake/ DESTINATION lib/cmake/fxsdk) -install(TARGETS fxsdk-gdb-bridge) +if(NOT WIN32) + install(TARGETS fxsdk-gdb-bridge) +endif() # fxgxa, fxg1a install(TARGETS fxgxa) install(FILES "${BIN}/fxg1a" TYPE BIN) diff --git a/README.md b/README.md index d2d3bab..9c12eb8 100644 --- a/README.md +++ b/README.md @@ -169,3 +169,24 @@ When configuring, you should set an install prefix that you have write access to ``` You can then proceed to install the cross-compiler. If in doubt about the order in which you need to install repositories, refer to the [GiteaPC README](https://gitea.planet-casio.com/Lephenixnoir/GiteaPC) or check the `giteapc.make` files of each repository, where dependencies are listed. + +## Building for Windows from Arch Linux using a cross-compiler + +⚠️ This is experimental/not yet officially supported. Intended to build fxlink only. + +_Credits to [Cahute](https://cahuteproject.org/guides/build.html) from which this process is based._ + +Install the cross-compiler and cross-libraries from AUR. + +```bash +% yay -S python python-toml mingw-w64 \ + mingw-w64-cmake mingw-w64-libusb mingw-w64-sdl2 mingw-w64-libpng \ + mingw-w64-ncurses +``` + +Configure and build. + +```bash +% x86_64-w64-mingw32-cmake -B build-win64 -DFXLINK_DISABLE_UDISKS2=1 -DFXLINK_DISABLE_POLL=1 +% make -C build-win64 +``` diff --git a/fxgxa/dump.c b/fxgxa/dump.c index 0c610f0..5575b6c 100644 --- a/fxgxa/dump.c +++ b/fxgxa/dump.c @@ -53,7 +53,7 @@ static int check_g1a(int test, struct g1a const *g1a, size_t size,char *status) m("Sequence 2 0x01 0x%02x", h->seq2); return (h->seq2 != 0x01) ? 1:0; case 5: - m("File size 1 %-8zu %u", size, + m("File size 1 %-8lu %u", (unsigned long)size, be32toh(h->filesize_be1)); return (be32toh(h->filesize_be1) != size) ? 2:0; case 6: @@ -66,7 +66,7 @@ static int check_g1a(int test, struct g1a const *g1a, size_t size,char *status) be16toh(h->checksum)); return (be16toh(h->checksum) != sum) ? 2:0; case 8: - m("File size 2 %-8zu %u", size, + m("File size 2 %-8lu %u", (unsigned long)size, be32toh(h->filesize_be2)); return (be32toh(h->filesize_be2) != size) ? 2:0; default: @@ -170,7 +170,7 @@ static int check_g3a(int test, struct g3a const *g3a, size_t size,char *status) m("Sequence 2 0x01 0x%02x", h->seq2); return (h->seq2 != 0x01) ? 1:0; case 5: - m("File size 1 %-8zu %u", size, + m("File size 1 %-8lu %u", (unsigned long)size, be32toh(h->filesize_be1)); return (be32toh(h->filesize_be1) != size) ? 2:0; case 6: @@ -183,7 +183,7 @@ static int check_g3a(int test, struct g3a const *g3a, size_t size,char *status) be16toh(h->checksum)); return (be16toh(h->checksum) != sum) ? 2:0; case 8: - m("File size 2 %-8zu %u", size - 0x7004, + m("File size 2 %-8lu %u", (unsigned long)size - 0x7004, be32toh(h->filesize_be2)); return (be32toh(h->filesize_be2) != size - 0x7004) ? 2:0; case 9: @@ -192,7 +192,7 @@ static int check_g3a(int test, struct g3a const *g3a, size_t size,char *status) be32toh(h->checksum_2)); return (be32toh(h->checksum_2) != sum2) ? 2:0; case 10: - m("File size 1 %-8zu %u", size, + m("File size 1 %-8lu %u", (unsigned long)size, be32toh(h->filesize_be3)); return (be32toh(h->filesize_be3) != size) ? 2:0; case 11: diff --git a/fxgxa/endianness.h b/fxgxa/endianness.h index 30361e2..5553d6f 100644 --- a/fxgxa/endianness.h +++ b/fxgxa/endianness.h @@ -24,6 +24,42 @@ #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) +#elif defined(__WINDOWS__) || defined(_WIN16) || defined(_WIN32) || defined(_WIN64) + + #include + + #if BYTE_ORDER == LITTLE_ENDIAN + #define htobe16(x) __builtin_bswap16(x) + #define htole16(x) (x) + #define be16toh(x) __builtin_bswap16(x) + #define le16toh(x) (x) + + #define htobe32(x) __builtin_bswap32(x) + #define htole32(x) (x) + #define be32toh(x) __builtin_bswap32(x) + #define le32toh(x) (x) + + #define htobe64(x) __builtin_bswap64(x) + #define htole64(x) (x) + #define be64toh(x) __builtin_bswap64(x) + #define le64toh(x) (x) + #elif BYTE_ORDER == BIG_ENDIAN + #define htobe16(x) (x) + #define htole16(x) __builtin_bswap16(x) + #define be16toh(x) (x) + #define le16toh(x) __builtin_bswap16(x) + + #define htobe32(x) (x) + #define htole32(x) __builtin_bswap32(x) + #define be32toh(x) (x) + #define le32toh(x) __builtin_bswap32(x) + + #define htobe64(x) (x) + #define htole64(x) __builtin_bswap64(x) + #define be64toh(x) (x) + #define le64toh(x) __builtin_bswap64(x) + #endif + #elif defined(__linux__) #include diff --git a/fxlink/main.c b/fxlink/main.c index 4a49f5d..9db1a64 100644 --- a/fxlink/main.c +++ b/fxlink/main.c @@ -237,7 +237,9 @@ int main(int argc, char **argv) while(repeat); } else if(mode == 't') { +#ifndef FXLINK_DISABLE_POLL rc = main_tui_interactive(context); +#endif } else if(mode == 'p') { rc = main_push(filter, &delay, context, argv + optind); diff --git a/fxlink/tui/command-util.c b/fxlink/tui/command-util.c index 93035c4..7e542e8 100644 --- a/fxlink/tui/command-util.c +++ b/fxlink/tui/command-util.c @@ -4,6 +4,9 @@ // \___/ License: MIT // //---------------------------------------------------------------------------// +#include +#ifndef FXLINK_DISABLE_POLL + #include "tui.h" #include "command-util.h" #include @@ -377,3 +380,5 @@ FXLINK_COMMAND("?cmdtree") node_dump(cmdtree, 0); return 0; } + +#endif diff --git a/fxlink/tui/commands.c b/fxlink/tui/commands.c index 5afa8b3..14e6c08 100644 --- a/fxlink/tui/commands.c +++ b/fxlink/tui/commands.c @@ -4,6 +4,9 @@ // \___/ License: MIT // //---------------------------------------------------------------------------// +#include +#ifndef FXLINK_DISABLE_POLL + #include "tui.h" #include "command-util.h" #include @@ -271,3 +274,5 @@ FXLINK_COMMAND("gintctl test all", DEVICE(fdev)) test_read_unaligned(fdev); return 0; } + +#endif diff --git a/fxlink/tui/tui-interactive.c b/fxlink/tui/tui-interactive.c index 5dc000b..1183461 100644 --- a/fxlink/tui/tui-interactive.c +++ b/fxlink/tui/tui-interactive.c @@ -4,6 +4,9 @@ // \___/ License: MIT // //---------------------------------------------------------------------------// +#include +#ifndef FXLINK_DISABLE_POLL + #include "../fxlink.h" #include "tui.h" #include @@ -202,24 +205,24 @@ static void TUI_render_transfers(void) if(!comm) continue; - struct fxlink_transfer *IN = comm->ftransfer_IN; - struct fxlink_transfer *OUT = comm->ftransfer_OUT; + struct fxlink_transfer *in = comm->ftransfer_IN; + struct fxlink_transfer *out = comm->ftransfer_OUT; - if(IN) { + if(in) { mvwaddstr(win, y, 1, fxlink_device_id(fdev)); mvwaddstr(win, y, 10, "IN"); - mvwaddstr(win, y, 16, fxlink_size_string(IN->msg.size)); + mvwaddstr(win, y, 16, fxlink_size_string(in->msg.size)); wmove(win, y, 26); - progress_bar(win, 32, IN->processed_size, IN->msg.size); + progress_bar(win, 32, in->processed_size, in->msg.size); has_transfers = true; y++; } - if(OUT) { + if(out) { mvwaddstr(win, y, 1, fxlink_device_id(fdev)); mvwaddstr(win, y, 10, "OUT"); - mvwaddstr(win, y, 16, fxlink_size_string(OUT->msg.size)); + mvwaddstr(win, y, 16, fxlink_size_string(out->msg.size)); has_transfers = true; y++; } @@ -259,10 +262,12 @@ static bool TUI_setup(void) memset(&TUI, 0, sizeof TUI); /* Set up the SINGWINCH handler */ +#if !defined(_WIN16) && !defined(_WIN32) && !defined(_WIN64) struct sigaction WINCH; sigaction(SIGWINCH, NULL, &WINCH); WINCH.sa_handler = TUI_SIGWINCH_handler; sigaction(SIGWINCH, &WINCH, NULL); +#endif /* Initialize the main screen */ initscr(); @@ -590,3 +595,5 @@ int main_tui_interactive(libusb_context *ctx) TUI_quit(); return 0; } + +#endif diff --git a/libfxlink/defs.c b/libfxlink/defs.c index a684532..a6a9074 100644 --- a/libfxlink/defs.c +++ b/libfxlink/defs.c @@ -47,7 +47,11 @@ char *fxlink_gen_file_name(char const *path, char const *name, time_t time_raw; struct tm time_bd; time(&time_raw); +#if defined(_WIN16) || defined(_WIN32) || defined(_WIN64) + time_bd = *localtime(&time_raw); +#else localtime_r(&time_raw, &time_bd); +#endif while(1) { asprintf(&filename, "%s/fxlink-%.16s-%04d.%02d.%02d-%02dh%02d-%d%s", @@ -67,6 +71,7 @@ char *fxlink_gen_file_name(char const *path, char const *name, return filename; } +#ifndef FXLINK_DISABLE_POLL int fxlink_multipoll(int timeout, struct pollfd *fds1, int count1, ...) { /* Convenience macro to iterate on file descriptor arrays */ @@ -104,6 +109,7 @@ int fxlink_multipoll(int timeout, struct pollfd *fds1, int count1, ...) free(concat); return rc; } +#endif /* FXLINK_DISABLE_POLL */ char const *fxlink_size_string(int bytes) { diff --git a/libfxlink/devices.c b/libfxlink/devices.c index 271e720..a1ca83e 100644 --- a/libfxlink/devices.c +++ b/libfxlink/devices.c @@ -635,6 +635,8 @@ bool fxlink_device_start_bulk_OUT(struct fxlink_device *fdev, // Polled file descriptor tracking //--- +#ifndef FXLINK_DISABLE_POLL + static void generate_poll_fds(struct fxlink_pollfds *tracker) { /* Get the set of libusb file descriptors to poll for news */ @@ -705,6 +707,8 @@ void fxlink_pollfds_stop(struct fxlink_pollfds *tracker) memset(tracker, 0, sizeof *tracker); } +#endif /* FXLINK_DISABLE_POLL */ + //--- // Device tracking //--- diff --git a/libfxlink/filter.c b/libfxlink/filter.c index 530ca7e..59195c1 100644 --- a/libfxlink/filter.c +++ b/libfxlink/filter.c @@ -29,7 +29,13 @@ static char *read_word(char const **input) { char const *str = *input; while(**input && isword(**input)) (*input)++; - return strndup(str, *input - str); + + char *rc = malloc(*input - str + 1); + if(!rc) + return NULL; + memcpy(rc, str, *input - str); + rc[*input - str] = 0; + return rc; } /* Reads a property from the input source. Advances *input and sets *name and diff --git a/libfxlink/include/fxlink/config.h.in b/libfxlink/include/fxlink/config.h.in index fa44496..446795b 100644 --- a/libfxlink/include/fxlink/config.h.in +++ b/libfxlink/include/fxlink/config.h.in @@ -13,5 +13,8 @@ /* Disable SDL2 interfaces. */ #cmakedefine FXLINK_DISABLE_SDL2 +/* Disable poll-based interfaces. */ +#cmakedefine FXLINK_DISABLE_POLL + /* fxSDK version */ #define FXLINK_VERSION "@CMAKE_PROJECT_VERSION@" diff --git a/libfxlink/include/fxlink/defs.h b/libfxlink/include/fxlink/defs.h index b2c2c8e..2e4b83a 100644 --- a/libfxlink/include/fxlink/defs.h +++ b/libfxlink/include/fxlink/defs.h @@ -12,7 +12,10 @@ #include #include #include -#include + +#ifndef FXLINK_DISABLE_POLL +# include +#endif static inline int min(int x, int y) { @@ -84,8 +87,10 @@ char const *fmt_to_ANSI(int format); char *fxlink_gen_file_name(char const *path, char const *name, char const *suffix); +#ifndef FXLINK_DISABLE_POLL /* Modified poll with a variable number of arrays. */ int fxlink_multipoll(int timeout, struct pollfd *fds1, int count1, ...); +#endif /* Write out the given size (in bytes) in a human-readable form. Returns a pointer to a statically-allocated string. */ diff --git a/libfxlink/include/fxlink/devices.h b/libfxlink/include/fxlink/devices.h index d06defb..4a5d6dc 100644 --- a/libfxlink/include/fxlink/devices.h +++ b/libfxlink/include/fxlink/devices.h @@ -48,8 +48,8 @@ #pragma once #include #include +#include #include -#include /* Device information tracked for every USB device. */ struct fxlink_device { @@ -255,6 +255,8 @@ void fxlink_device_cleanup(struct fxlink_device *fdev); // notification API. //--- +#ifndef FXLINK_DISABLE_POLL + /* Tracker for libusb file descriptors to be polled in a main loop. */ struct fxlink_pollfds { /* libusb context to be tracked (must remain constant) */ @@ -274,6 +276,8 @@ void fxlink_pollfds_track(struct fxlink_pollfds *tracker, libusb_context *ctx); called before the tracker structure gets destroyed. */ void fxlink_pollfds_stop(struct fxlink_pollfds *tracker); +#endif /* FXLINK_DISABLE_POLL */ + //--- // Device tracking // diff --git a/libfxlink/logging.c b/libfxlink/logging.c index 55daca6..b6d0f84 100644 --- a/libfxlink/logging.c +++ b/libfxlink/logging.c @@ -84,7 +84,11 @@ int hlog(char const *fmt, ...) { time_t t = time(NULL); struct tm tm; +#if defined(_WIN16) || defined(_WIN32) || defined(_WIN64) + tm = *localtime(&t); +#else localtime_r(&t, &tm); +#endif flog(FMT_WHITE | FMT_DIM, "[%02d:%02d] ", tm.tm_hour, tm.tm_min); LOG_VA_ARGS(fmt, flogv(FMT_YELLOW | FMT_DIM, fmt, _args));