Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement hotreloading for macOS and Windows and other bugfixes #74

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ nob
nob.old
nob.exe
nob.exe.old
nob.obj
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ $ wine ./build/musializer.exe

## Hot Reloading

**Only on Linux for now**

Edit `./build/config.h` and enable `MUSIALIZER_HOTRELOAD`.

```console
Expand Down
2 changes: 1 addition & 1 deletion nob.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ void generate_default_config(Nob_String_Builder *content)
# endif
#endif
nob_sb_append_cstr(content, "\n");
nob_sb_append_cstr(content, "//// Moves everything in src/plub.c to a separate \"DLL\" so it can be hotreloaded. Works only for Linux right now\n");
nob_sb_append_cstr(content, "//// Moves everything in src/plug.c to a separate \"DLL\" so it can be hotreloaded.\n");
nob_sb_append_cstr(content, "// #define MUSIALIZER_HOTRELOAD\n");
nob_sb_append_cstr(content, "\n");
nob_sb_append_cstr(content, "//// Unfinished feature that enables capturing sound from the mic.\n");
Expand Down
5 changes: 4 additions & 1 deletion src/hotreload_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
#include <dlfcn.h>

#include <raylib.h>

#include "hotreload.h"

#if defined(__APPLE__) || defined(__MACH__)
static const char *libplug_file_name = "libplug.dylib";
#else
static const char *libplug_file_name = "libplug.so";
#endif
static void *libplug = NULL;

#define PLUG(name, ...) name##_t *name = NULL;
Expand Down
38 changes: 38 additions & 0 deletions src/hotreload_windows.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#define NOUSER
#include <windows.h>

#include <raylib.h>
#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;
}
8 changes: 4 additions & 4 deletions src/nob.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ int nob_file_exists(const char *file_path);
# elif defined(__clang__)
# define NOB_REBUILD_URSELF(binary_path, source_path) "clang", "-o", binary_path, source_path
# elif defined(_MSC_VER)
# define NOB_REBUILD_URSELF(binary_path, source_path) "cl.exe", source_path
# define NOB_REBUILD_URSELF(binary_path, source_path) "cl.exe", nob_temp_sprintf("/Fe%s", binary_path), source_path
# endif
# else
# define NOB_REBUILD_URSELF(binary_path, source_path) "cc", "-o", binary_path, source_path
Expand Down Expand Up @@ -364,9 +364,9 @@ struct dirent

typedef struct DIR DIR;

DIR *opendir(const char *dirpath);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);
static DIR *opendir(const char *dirpath);
static struct dirent *readdir(DIR *dirp);
static int closedir(DIR *dirp);
#endif // _WIN32
// minirent.h HEADER END ////////////////////////////////////////

Expand Down
60 changes: 51 additions & 9 deletions src/nob_macos.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,49 @@ bool build_musializer(void)
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);
procs.count = 0;
cmd.count = 0;
nob_cmd_append(&cmd, "clang");
nob_cmd_append(&cmd, "-Wall", "-Wextra", "-ggdb");
nob_cmd_append(&cmd, "-I./build/");
nob_cmd_append(&cmd, "-I./raylib/raylib-"RAYLIB_VERSION"/src/");
nob_cmd_append(&cmd, "-fPIC", "-dynamiclib");
nob_cmd_append(&cmd, "-o", "./build/libplug.dylib");
nob_cmd_append(&cmd,
"./src/plug.c",
"./src/ffmpeg_linux.c");
nob_cmd_append(&cmd,
nob_temp_sprintf("-L./build/raylib/%s", MUSIALIZER_TARGET_NAME),
"-lraylib");
nob_cmd_append(&cmd, "-lm", "-ldl", "-lpthread");
nob_da_append(&procs, nob_cmd_run_async(cmd));

cmd.count = 0;
nob_cmd_append(&cmd, "clang");
nob_cmd_append(&cmd, "-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_linux.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,
nob_temp_sprintf("-L./build/raylib/%s", MUSIALIZER_TARGET_NAME),
"-lraylib");
nob_cmd_append(&cmd, "-framework", "CoreVideo");
nob_cmd_append(&cmd, "-framework", "IOKit");
nob_cmd_append(&cmd, "-framework", "Cocoa");
nob_cmd_append(&cmd, "-framework", "GLUT");
nob_cmd_append(&cmd, "-framework", "OpenGL");
nob_cmd_append(&cmd, "-lm", "-ldl", "-lpthread");
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, "clang");
Expand Down Expand Up @@ -97,20 +138,21 @@ bool build_raylib(void)
if (!nob_cmd_run_sync(cmd)) nob_return_defer(false);
}
#else
const char *libraylib_path = nob_temp_sprintf("%s/libraylib.so", build_path);
const char *libraylib_path = nob_temp_sprintf("%s/libraylib.dylib", build_path);

if (nob_needs_rebuild(libraylib_path, object_files.items, object_files.count)) {
if (config.target != TARGET_LINUX) {
nob_log(NOB_ERROR, "TODO: dynamic raylib for %s is not supported yet", NOB_ARRAY_GET(target_names, config.target));
nob_return_defer(false);
}
nob_cmd_append(&cmd, "cc");
nob_cmd_append(&cmd, "-shared");
nob_cmd_append(&cmd, "clang");
nob_cmd_append(&cmd, "-dynamiclib");
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, "-framework", "CoreVideo");
nob_cmd_append(&cmd, "-framework", "IOKit");
nob_cmd_append(&cmd, "-framework", "Cocoa");
nob_cmd_append(&cmd, "-framework", "GLUT");
nob_cmd_append(&cmd, "-framework", "OpenGL");
if (!nob_cmd_run_sync(cmd)) nob_return_defer(false);
}
#endif // MUSIALIZER_HOTRELOAD
Expand Down
59 changes: 54 additions & 5 deletions src/nob_win64_mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ 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;
#ifdef _WIN32
// On windows, mingw doesn't have the `x86_64-w64-mingw32-` prefix for windres.
Expand All @@ -22,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, "-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, "-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, "-Wall", "-Wextra", "-ggdb");
Expand Down Expand Up @@ -104,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:
Expand Down
62 changes: 51 additions & 11 deletions src/nob_win64_msvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,47 @@ 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",
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/");
Expand All @@ -25,9 +56,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",
nob_temp_sprintf("/LIBPATH:build/raylib/%s", MUSIALIZER_TARGET_NAME),
Expand Down Expand Up @@ -71,6 +100,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));
Expand All @@ -81,7 +113,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)) {
Expand All @@ -94,10 +125,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, nob_temp_sprintf("/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);
Expand Down
Loading