From b4f41103f2c673033367b0815e59df046df70cc0 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 8 Sep 2024 17:32:24 +0100 Subject: [PATCH] Test hot reloading --- .gitignore | 2 ++ compile | 49 +++++++++++++++++++++---- src/game.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/game.h | 22 ++++++++++++ src/main.c | 29 +++++++++++++++ 5 files changed, 198 insertions(+), 6 deletions(-) create mode 100644 src/game.c create mode 100644 src/game.h diff --git a/.gitignore b/.gitignore index 6e47b57..299d43d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .cache compile_commands.json main +*.so +*.o diff --git a/compile b/compile index 3cacbdd..2cf675c 100755 --- a/compile +++ b/compile @@ -1,9 +1,46 @@ #!/bin/bash -CC=clang -CFLAGS="-g -Wall $(pkg-config --cflags sdl2)" -LIBS="$(pkg-config --libs sdl2)" -SRC=src/*.c -OUT=main +BUILD_TYPE="debug" -(set -x ; $CC $CFLAGS $LIBS $SRC -o $OUT) +while [[ $# > 0 ]];do + case $1 in + --release) + BUILD_TYPE="release" + shift + ;; + *|-*|--*) + echo "Unknown option $1" + exit 1 + ;; + esac +done + +CC=clang +CFLAGS="-Wall $(pkg-config --cflags sdl2)" +LIBS="$(pkg-config --libs sdl2)" +MAIN=src/main.c +MAIN_FLAGS="" +GAME=src/game.c +GAME_FLAGS="-DNDEBUG" +OUT=main +GAME_OUT="" + +if [[ $BUILD_TYPE == "debug" ]]; then + CFLAGS+=" -g" + MAIN_FLAGS="-ldl -Wl,-rpath,\$ORIGIN" + GAME_FLAGS+=" -fPIC -shared" + GAME_OUT="-o game.so" + MAIN+=" src/game.c" +else + CFLAGS+=" -O3" + MAIN_FLAGS="-DNDEBUG" + GAME_FLAGS+=" -c" + MAIN+=" game.o" +fi + +LOCKFILE="game.so.lock" +touch $LOCKFILE && (set -x ; $CC $CFLAGS $GAME_FLAGS $LIBS $GAME $GAME_OUT) +if [[ -f $LOCKFILE ]];then + rm $LOCKFILE +fi +(set -x ; $CC $CFLAGS $MAIN_FLAGS $LIBS $MAIN -o $OUT) diff --git a/src/game.c b/src/game.c new file mode 100644 index 0000000..484b825 --- /dev/null +++ b/src/game.c @@ -0,0 +1,102 @@ +#include "game.h" + +#if DEBUG +#include +#include +#include +#include +#include + +#define LIB "game.so" +#define LOCKFILE "game.so.lock" + +static void *handle = NULL; +static long int last_mtime; +void (*update_character)(int window_height) = NULL; +void (*render_character)(SDL_Renderer *renderer) = NULL; + +bool load_symbols(void) { + struct stat st; + if (stat(LOCKFILE, &st) == 0) { + // If lock file exists, don't reload the library + return true; + } + + if (stat(LIB, &st) != 0) { + perror("Error checking library stat: "); + return false; + } + + long int mtime = st.st_mtim.tv_sec * 1000000000 + st.st_mtim.tv_nsec; + if (mtime == last_mtime) { + return true; + } + + last_mtime = mtime; + + if (handle) { + close_library(); + } + + handle = dlopen(LIB, RTLD_NOW | RTLD_GLOBAL); + if (!handle) { + fprintf(stderr, "Failed to load library: %s\n", dlerror()); + return false; + } + + dlerror(); // Clear errors + + *(void **)(&update_character) = dlsym(handle, "update_character"); + *(void **)(&render_character) = dlsym(handle, "render_character"); + + char *error = dlerror(); + if (error != NULL) { + fprintf(stderr, "Failed to load function symbol: %s", error); + return false; + } + + return true; +} + +void close_library(void) { + if (handle) { + dlclose(handle); + handle = NULL; + } +} +#else +#include "SDL_rect.h" +#include "SDL_render.h" + +typedef struct state State; +struct state { + float delta; + float speed; + SDL_Rect character; +}; + +static State game = { + .delta = 1.f / 60.f, + .speed = 1600.f, + .character = {.x = 375, .y = 0, .w = 50, .h = 50}, +}; + +void update_character(int window_height) { + game.character.y += game.speed * game.delta; + if (game.character.y < 0 || + game.character.y + game.character.h > window_height) { + game.speed *= -1.f; + + if (game.character.y < 0) { + game.character.y = 0; + } else { + game.character.y = window_height - game.character.h; + } + } +} + +void render_character(SDL_Renderer *renderer) { + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderFillRect(renderer, &game.character); +} +#endif diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..40fd311 --- /dev/null +++ b/src/game.h @@ -0,0 +1,22 @@ +#pragma once + +#include "SDL_render.h" + +#ifdef NDEBUG +#define DEBUG 0 +#else +#define DEBUG 1 +#endif + +#if DEBUG +#include + +bool load_symbols(void); +void close_library(void); + +extern void (*update_character)(int window_height); +extern void (*render_character)(SDL_Renderer *renderer); +#else +void update_character(int window_height); +void render_character(SDL_Renderer *renderer); +#endif diff --git a/src/main.c b/src/main.c index cbb5022..6ac689d 100644 --- a/src/main.c +++ b/src/main.c @@ -1,9 +1,16 @@ +#include "game.h" #include #include #include #include #include +#ifdef NDEBUG +#define DEBUG 0 +#else +#define DEBUG 1 +#endif + #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 @@ -21,6 +28,13 @@ int main(void) { SDL_Event event = {0}; +#if DEBUG + if (!load_symbols()) { + fprintf(stderr, "Failed to load game library\n"); + return 1; + } +#endif + while (running) { while (SDL_PollEvent(&event)) { switch (event.type) { @@ -30,13 +44,28 @@ int main(void) { } } +#if DEBUG + if (!load_symbols()) { + fprintf(stderr, "Failed to load game library\n"); + return 1; + } +#endif + + update_character(WINDOW_HEIGHT); + SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderClear(renderer); + render_character(renderer); + SDL_RenderPresent(renderer); } +#if DEBUG + close_library(); +#endif + SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window);