This project demonstrates a framework for dynamically loading shared libraries at runtime, enabling hot-reloading functionality. The framework is designed to facilitate efficient development and deployment of modular systems where updates to library functions do not require restarting the application.
- In static linking, all the required libraries are bundled with the executable at compile-time.
- Pros:
- Single executable file; no dependency on external libraries at runtime.
- Faster execution since no linking is required at runtime.
- Cons:
- Larger binary size.
- Requires recompilation for any library updates.
- Dynamic linking resolves library references at runtime using shared objects (
.sofiles in Linux). - Pros:
- Smaller binary size.
- Libraries can be updated without recompiling the application.
- Enables features like hot-reloading.
- Cons:
- Slight overhead due to runtime linking.
- Dependency on external library files.
This framework extends the concept of dynamic linking to implement hot-reloading:
- Dynamically loaded libraries can be updated without restarting the application.
- The framework monitors libraries for changes and reloads them automatically.
The framework consists of:
-
Core Functions (
hr.h,hr.c)- Provides the APIs for loading, unloading, and reloading shared libraries dynamically.
- Monitors file modification timestamps to detect changes and trigger reloads.
-
Main Program (
main.c)- Demonstrates the use of the provided APIs to dynamically load and invoke functions from shared libraries.
-
Shared Libraries (
library1.c,library2.c)- Example libraries containing functions that can be hot-reloaded.
-
Script (
script.sh)- Automates the process of compilation and execution for the framework and libraries.
git clone https://github.com/TalhaSikandar/bluefin_hr
cd bluefin_hrhr.h/hr.c: Core hot-reloading wrapper implementation.main.c: Demonstrates the API usage.library1.c/library2.c: Example shared libraries.script.sh: Automates building and running the example program.
Run the provided script:
./script.shWhat it does:
- Creates an
output/directory for binaries. - Compiles
main.cinto the main program. - Compiles
library1.candlibrary2.cinto shared libraries (.sofiles).
./output/mainBehavior:
- Dynamically loads functions from
library1.soandlibrary2.so. - Invokes library functions via the
generic_callAPI. - Monitors library modification timestamps to detect updates.
Here’s a step-by-step guide to integrating the framework:
Create an instance of the HotReloadLibrary structure for each library you want to load.
Use load_library to load a shared library and its functions dynamically:
const char *functions[] = {"func1", "func2"}; // Function names in the library
HotReloadLibrary my_lib;
if (load_library(&my_lib, "path/to/library.so", functions, 2) != 0) {
fprintf(stderr, "Failed to load library\n");
return -1;
}Use generic_call to invoke a function from the library:
generic_call(&my_lib, "func1", params);Call check_and_reload_library periodically to check for updates and reload the library if it has been modified:
check_and_reload_library(&my_lib, "path/to/library.so", functions, 2);Clean up resources when the library is no longer needed:
unload_library(&my_lib);Modify script.sh to adapt the framework to your project:
- Update
FLASHESto include all.cfiles for your shared libraries. - Update
MAIN_PROGRAM_SRCto point to your main application.
Example:
FLASHES=("libmath.c" "libutils.c")
MAIN_PROGRAM_SRC="app_main.c"Run the script to build your program:
./script.sh- Use the hot-reloading API to manage shared modules in systems requiring frequent updates (e.g., plugins, game engines, or modular applications).
- Monitor changes to specific libraries using
check_and_reload_libraryin a separate thread or main event loop.
- Modify one of the shared libraries (e.g.,
library1.c). - Recompile only the library:
gcc -shared -o output/library1.so library1.c
- Observe the main program detecting the change and reloading the updated library.
- Ensure Thread-Safety: If using multiple threads, synchronize access to shared libraries.
- Validate Library Paths: Use absolute paths to avoid runtime errors.
- Handle Errors Gracefully: Check return values from all API functions to detect failures early.