Test hot reloading
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,5 @@
 | 
			
		||||
.cache
 | 
			
		||||
compile_commands.json
 | 
			
		||||
main
 | 
			
		||||
*.so
 | 
			
		||||
*.o
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										49
									
								
								compile
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								src/game.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/game.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										22
									
								
								src/game.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										29
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								src/main.c
									
									
									
									
									
								
							@@ -1,9 +1,16 @@
 | 
			
		||||
#include "game.h"
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
#include <SDL2/SDL_events.h>
 | 
			
		||||
#include <SDL2/SDL_render.h>
 | 
			
		||||
#include <SDL2/SDL_video.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user