Test hot reloading

This commit is contained in:
Abdelrahman Said 2024-09-08 17:32:24 +01:00
parent 8ad090b582
commit b4f41103f2
5 changed files with 198 additions and 6 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.cache .cache
compile_commands.json compile_commands.json
main main
*.so
*.o

49
compile
View File

@ -1,9 +1,46 @@
#!/bin/bash #!/bin/bash
CC=clang BUILD_TYPE="debug"
CFLAGS="-g -Wall $(pkg-config --cflags sdl2)"
LIBS="$(pkg-config --libs sdl2)"
SRC=src/*.c
OUT=main
(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)

102
src/game.c Normal file
View File

@ -0,0 +1,102 @@
#include "game.h"
#if DEBUG
#include <dlfcn.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#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

22
src/game.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "SDL_render.h"
#ifdef NDEBUG
#define DEBUG 0
#else
#define DEBUG 1
#endif
#if DEBUG
#include <stdbool.h>
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

View File

@ -1,9 +1,16 @@
#include "game.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <SDL2/SDL_render.h> #include <SDL2/SDL_render.h>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <stdbool.h> #include <stdbool.h>
#ifdef NDEBUG
#define DEBUG 0
#else
#define DEBUG 1
#endif
#define WINDOW_WIDTH 800 #define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600 #define WINDOW_HEIGHT 600
@ -21,6 +28,13 @@ int main(void) {
SDL_Event event = {0}; SDL_Event event = {0};
#if DEBUG
if (!load_symbols()) {
fprintf(stderr, "Failed to load game library\n");
return 1;
}
#endif
while (running) { while (running) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { 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_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
render_character(renderer);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }
#if DEBUG
close_library();
#endif
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window); SDL_DestroyWindow(window);