From 3505ee7c17c7e9fd296f3d0ba0b09625adaa19e2 Mon Sep 17 00:00:00 2001 From: MarkosTh09 Date: Mon, 26 Feb 2024 21:21:37 +0400 Subject: [PATCH] add hotreload support for windows --- .gitignore | 1 + src/hotreload_windows.c | 38 ++++++++++++++++++++++++ src/nob_win64_mingw.c | 60 +++++++++++++++++++++++++++++++++---- src/nob_win64_msvc.c | 66 +++++++++++++++++++++++++++++++++-------- src/plug.c | 14 ++++++--- 5 files changed, 158 insertions(+), 21 deletions(-) create mode 100644 src/hotreload_windows.c diff --git a/.gitignore b/.gitignore index 7384fff..731bedf 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ nob nob.old nob.exe nob.exe.old +nob.obj diff --git a/src/hotreload_windows.c b/src/hotreload_windows.c new file mode 100644 index 0000000..b4e2ec2 --- /dev/null +++ b/src/hotreload_windows.c @@ -0,0 +1,38 @@ +#include +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#define NOUSER +#include + +#include +#include "hotreload.h" + +static const char *libplug_file_name = "libplug.dll"; +static void *libplug = NULL; + +#define PLUG(name, ...) name##_t *name = NULL; +LIST_OF_PLUGS +#undef PLUG + +bool reload_libplug(void) +{ + if (libplug != NULL) FreeLibrary(libplug); + + libplug = LoadLibrary(libplug_file_name); + if (libplug == NULL) { + TraceLog(LOG_ERROR, "HOTRELOAD: could not load %s: %s", libplug_file_name, GetLastError()); + return false; + } + + #define PLUG(name, ...) \ + name = GetProcAddress(libplug, #name); \ + if (name == NULL) { \ + TraceLog(LOG_ERROR, "HOTRELOAD: could not find %s symbol in %s: %s", \ + #name, libplug_file_name, GetLastError()); \ + return false; \ + } + LIST_OF_PLUGS + #undef PLUG + + return true; +} \ No newline at end of file diff --git a/src/nob_win64_mingw.c b/src/nob_win64_mingw.c index 02cb8ce..5213ce4 100644 --- a/src/nob_win64_mingw.c +++ b/src/nob_win64_mingw.c @@ -6,9 +6,6 @@ bool build_musializer(void) Nob_Cmd cmd = {0}; Nob_Procs procs = {0}; -#ifdef MUSIALIZER_HOTRELOAD -#error "TODO: hotreloading is not supported on TARGET_WIN64_MINGW yet" -#else cmd.count = 0; #ifdef _WIN32 // On windows, mingw doesn't have the `x86_64-w64-mingw32-` prefix for windres. @@ -21,7 +18,47 @@ bool build_musializer(void) nob_cmd_append(&cmd, "-O", "coff"); nob_cmd_append(&cmd, "-o", "./build/musializer.res"); if (!nob_cmd_run_sync(cmd)) nob_return_defer(false); +#ifdef MUSIALIZER_HOTRELOAD + procs.count = 0; + cmd.count = 0; + nob_cmd_append(&cmd, "x86_64-w64-mingw32-gcc"); + nob_cmd_append(&cmd, "-mwindows", "-Wall", "-Wextra", "-ggdb"); + nob_cmd_append(&cmd, "-I./build/"); + nob_cmd_append(&cmd, "-I./raylib/raylib-"RAYLIB_VERSION"/src/"); + nob_cmd_append(&cmd, "-fPIC", "-shared"); + nob_cmd_append(&cmd, "-static-libgcc"); + nob_cmd_append(&cmd, "-o", "./build/libplug.dll"); + nob_cmd_append(&cmd, + "./src/plug.c", + "./src/ffmpeg_windows.c"); + nob_cmd_append(&cmd, + "-L./build", + "-l:raylib.dll"); + nob_cmd_append(&cmd, "-lwinmm", "-lgdi32"); + nob_da_append(&procs, nob_cmd_run_async(cmd)); + cmd.count = 0; + nob_cmd_append(&cmd, "x86_64-w64-mingw32-gcc"); + nob_cmd_append(&cmd, "-mwindows", "-Wall", "-Wextra", "-ggdb"); + nob_cmd_append(&cmd, "-I./build/"); + nob_cmd_append(&cmd, "-I./raylib/raylib-"RAYLIB_VERSION"/src/"); + nob_cmd_append(&cmd, "-o", "./build/musializer"); + nob_cmd_append(&cmd, + "./src/musializer.c", + "./src/hotreload_windows.c"); + nob_cmd_append(&cmd, + "-Wl,-rpath=./build/", + "-Wl,-rpath=./", + nob_temp_sprintf("-Wl,-rpath=./build/raylib/%s", MUSIALIZER_TARGET_NAME), + // NOTE: just in case somebody wants to run musializer from within the ./build/ folder + nob_temp_sprintf("-Wl,-rpath=./raylib/%s", MUSIALIZER_TARGET_NAME)); + nob_cmd_append(&cmd, + "-L./build", + "-l:raylib.dll"); + nob_cmd_append(&cmd, "-lwinmm", "-lgdi32"); + nob_da_append(&procs, nob_cmd_run_async(cmd)); + if (!nob_procs_wait(procs)) nob_return_defer(false); +#else cmd.count = 0; nob_cmd_append(&cmd, "x86_64-w64-mingw32-gcc"); nob_cmd_append(&cmd, "-mwindows", "-Wall", "-Wextra", "-ggdb"); @@ -95,7 +132,7 @@ bool build_raylib() const char *libraylib_path = nob_temp_sprintf("%s/libraylib.a", build_path); if (nob_needs_rebuild(libraylib_path, object_files.items, object_files.count)) { - nob_cmd_append(&cmd, "ar", "-crs", libraylib_path); + nob_cmd_append(&cmd, "x86_64-w64-mingw32-ar", "-crs", libraylib_path); for (size_t i = 0; i < NOB_ARRAY_LEN(raylib_modules); ++i) { const char *input_path = nob_temp_sprintf("%s/%s.o", build_path, raylib_modules[i]); nob_cmd_append(&cmd, input_path); @@ -103,7 +140,20 @@ bool build_raylib() if (!nob_cmd_run_sync(cmd)) nob_return_defer(false); } #else -#error "TODO: dynamic raylib is not supported for TARGET_WIN64_MINGW" + // it cannot load the raylib dll if it not in the same folder as the executable + const char *libraylib_path = "./build/raylib.dll"; + + if (nob_needs_rebuild(libraylib_path, object_files.items, object_files.count)) { + nob_cmd_append(&cmd, "x86_64-w64-mingw32-gcc"); + nob_cmd_append(&cmd, "-shared"); + nob_cmd_append(&cmd, "-o", libraylib_path); + for (size_t i = 0; i < NOB_ARRAY_LEN(raylib_modules); ++i) { + const char *input_path = nob_temp_sprintf("%s/%s.o", build_path, raylib_modules[i]); + nob_cmd_append(&cmd, input_path); + } + nob_cmd_append(&cmd, "-lwinmm", "-lgdi32"); + if (!nob_cmd_run_sync(cmd)) nob_return_defer(false); + } #endif // MUSIALIZER_HOTRELOAD defer: diff --git a/src/nob_win64_msvc.c b/src/nob_win64_msvc.c index 5633c8d..2126378 100644 --- a/src/nob_win64_msvc.c +++ b/src/nob_win64_msvc.c @@ -7,16 +7,49 @@ bool build_musializer(void) Nob_Cmd cmd = {0}; Nob_Procs procs = {0}; -#ifdef MUSIALIZER_HOTRELOAD - nob_log(NOB_ERROR, "TODO: hotreloading is not supported on %s yet", NOB_ARRAY_GET(target_names, config.target)); - nob_return_defer(false); -#else cmd.count = 0; nob_cmd_append(&cmd, "rc"); nob_cmd_append(&cmd, "/fo", "./build/musializer.res"); nob_cmd_append(&cmd, "./src/musializer.rc"); // NOTE: Do not change the order of commandline arguments to rc. Their argparser is weird. if (!nob_cmd_run_sync(cmd)) nob_return_defer(false); +#ifdef MUSIALIZER_HOTRELOAD + procs.count = 0; + cmd.count = 0; + nob_cmd_append(&cmd, "cl.exe"); + nob_cmd_append(&cmd, "/LD"); + nob_cmd_append(&cmd, "/Fobuild\\", "/Fe./build/libplug.dll"); + nob_cmd_append(&cmd, "/I", "./build/"); + nob_cmd_append(&cmd, "/I", "./raylib/raylib-"RAYLIB_VERSION"/src/"); + nob_cmd_append(&cmd, + "src/plug.c", + "src/ffmpeg_windows.c"); + nob_cmd_append(&cmd, + "/link", + nob_temp_sprintf("/LIBPATH:build/raylib/%s", MUSIALIZER_TARGET_NAME), + "raylib.lib"); + nob_cmd_append(&cmd, "Winmm.lib", "gdi32.lib", "User32.lib", "Shell32.lib"); + nob_da_append(&procs, nob_cmd_run_async(cmd)); + + cmd.count = 0; + nob_cmd_append(&cmd, "cl.exe"); + nob_cmd_append(&cmd, "/I", "./build/"); + nob_cmd_append(&cmd, "/I", "./raylib/raylib-"RAYLIB_VERSION"/src/"); + nob_cmd_append(&cmd, "/Fobuild\\", "/Febuild\\musializer.exe"); + nob_cmd_append(&cmd, + "./src/musializer.c", + "./src/hotreload_windows.c", + ); + nob_cmd_append(&cmd, + "/link", + "/SUBSYSTEM:WINDOWS", + "/entry:mainCRTStartup", + nob_temp_sprintf("/LIBPATH:build/raylib/%s", MUSIALIZER_TARGET_NAME), + "raylib.lib"); + nob_cmd_append(&cmd, "Winmm.lib", "gdi32.lib", "User32.lib", "Shell32.lib", "./build/musializer.res"); + nob_da_append(&procs, nob_cmd_run_async(cmd)); + if (!nob_procs_wait(procs)) nob_return_defer(false); +#else cmd.count = 0; nob_cmd_append(&cmd, "cl.exe"); nob_cmd_append(&cmd, "/I", "./build/"); @@ -25,9 +58,7 @@ bool build_musializer(void) nob_cmd_append(&cmd, "./src/musializer.c", "./src/plug.c", - "./src/ffmpeg_windows.c" - // TODO: building resource file is not implemented for TARGET_WIN64_MSVC - ); + "./src/ffmpeg_windows.c"); nob_cmd_append(&cmd, "/link", "/SUBSYSTEM:WINDOWS", @@ -73,6 +104,9 @@ bool build_raylib(void) if (nob_needs_rebuild(output_path, &input_path, 1)) { cmd.count = 0; nob_cmd_append(&cmd, "cl.exe", "/DPLATFORM_DESKTOP"); + #ifdef MUSIALIZER_HOTRELOAD + nob_cmd_append(&cmd, "/DBUILD_LIBTYPE_SHARED"); + #endif nob_cmd_append(&cmd, "/I", "./raylib/raylib-"RAYLIB_VERSION"/src/external/glfw/include"); nob_cmd_append(&cmd, "/c", input_path); nob_cmd_append(&cmd, nob_temp_sprintf("/Fo%s", output_path)); @@ -83,7 +117,6 @@ bool build_raylib(void) cmd.count = 0; if (!nob_procs_wait(procs)) nob_return_defer(false); - #ifndef MUSIALIZER_HOTRELOAD const char *libraylib_path = nob_temp_sprintf("%s/raylib.lib", build_path); if (nob_needs_rebuild(libraylib_path, object_files.items, object_files.count)) { @@ -96,10 +129,19 @@ bool build_raylib(void) if (!nob_cmd_run_sync(cmd)) nob_return_defer(false); } #else - nob_log(NOB_WARNING, "TODO: dynamic raylib for %s is not supported yet", NOB_ARRAY_GET(target_names, config.target)); - nob_return_defer(false); + if (nob_needs_rebuild("./build/raylib.dll", object_files.items, object_files.count)) { + nob_cmd_append(&cmd, "link.exe", "/DLL"); + for (size_t i = 0; i < NOB_ARRAY_LEN(raylib_modules); ++i) { + const char *input_path = nob_temp_sprintf("%s/%s.obj", build_path, raylib_modules[i]); + nob_cmd_append(&cmd, input_path); + } + nob_cmd_append(&cmd, "Winmm.lib", "gdi32.lib", "User32.lib", "Shell32.lib"); + nob_cmd_append(&cmd, nob_temp_sprintf("/IMPLIB:%s/raylib.lib", build_path)); + nob_cmd_append(&cmd, "/OUT:./build/raylib.dll"); + if (!nob_cmd_run_sync(cmd)) nob_return_defer(false); + } #endif // MUSIALIZER_HOTRELOAD - + defer: nob_cmd_free(cmd); nob_da_free(object_files); @@ -115,4 +157,4 @@ bool build_dist(void) nob_log(NOB_ERROR, "TODO: Creating distro for MSVC build is not implemented yet"); return false; #endif // MUSIALIZER_HOTRELOAD -} +} \ No newline at end of file diff --git a/src/plug.c b/src/plug.c index 6d682eb..2df6059 100644 --- a/src/plug.c +++ b/src/plug.c @@ -109,6 +109,12 @@ void *plug_load_resource(const char *file_path, size_t *size) # define subcc(a, b) ((a)-(b)) #endif +#ifdef _WIN32 +#define MUSIALIZER_PLUG __declspec(dllexport) +#else +#define MUSIALIZER_PLUG +#endif + typedef struct { char *file_path; Music music; @@ -1627,7 +1633,7 @@ static void rendering_screen(void) } } -void plug_init(void) +MUSIALIZER_PLUG void plug_init(void) { p = malloc(sizeof(*p)); assert(p != NULL && "Buy more RAM lol"); @@ -1663,7 +1669,7 @@ void plug_init(void) SetMasterVolume(0.5); } -Plug *plug_pre_reload(void) +MUSIALIZER_PLUG Plug *plug_pre_reload(void) { for (size_t i = 0; i < p->tracks.count; ++i) { Track *it = &p->tracks.items[i]; @@ -1673,7 +1679,7 @@ Plug *plug_pre_reload(void) return p; } -void plug_post_reload(Plug *pp) +MUSIALIZER_PLUG void plug_post_reload(Plug *pp) { p = pp; for (size_t i = 0; i < p->tracks.count; ++i) { @@ -1690,7 +1696,7 @@ void plug_post_reload(Plug *pp) p->circle_power_location = GetShaderLocation(p->circle, "power"); } -void plug_update(void) +MUSIALIZER_PLUG void plug_update(void) { BeginDrawing(); ClearBackground(COLOR_BACKGROUND);