aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2024-11-28 21:20:07 +0100
committerGitHub <noreply@github.com>2024-11-28 21:20:07 +0100
commit314c41ef33a2d11e4313ecca0c708b8d02cd59d7 (patch)
tree47745fb861343c0dd491bba88ca196d8d2c282ab /core
parent6d83755e9239ea7e4fb6a24d91c9bd8f4148213b (diff)
parent1cece52359ec32d3b82b2f419faceb2e323ee6a1 (diff)
Merge pull request #4534 from laytan/dynlib-unload-before-load
dynlib: unload library before loading again & add LIBRARY_FILE_EXTENSION constant
Diffstat (limited to 'core')
-rw-r--r--core/dynlib/example/example.odin12
-rw-r--r--core/dynlib/lib.odin36
-rw-r--r--core/dynlib/lib_js.odin2
-rw-r--r--core/dynlib/lib_unix.odin2
-rw-r--r--core/dynlib/lib_windows.odin2
5 files changed, 36 insertions, 18 deletions
diff --git a/core/dynlib/example/example.odin b/core/dynlib/example/example.odin
index f12233b0a..78fb5a98c 100644
--- a/core/dynlib/example/example.odin
+++ b/core/dynlib/example/example.odin
@@ -21,12 +21,14 @@ Symbols :: struct {
main :: proc() {
sym: Symbols
+ LIB_PATH :: "lib." + dynlib.LIBRARY_FILE_EXTENSION
+
// Load symbols from `lib.dll` into Symbols struct.
// Each struct field is prefixed with `foo_` before lookup in the DLL's symbol table.
// The library's Handle (to unload) will be stored in `sym._my_lib_handle`. This way you can load multiple DLLs in one struct.
- count, ok := dynlib.initialize_symbols(&sym, "lib.dll", "foo_", "_my_lib_handle")
+ count, ok := dynlib.initialize_symbols(&sym, LIB_PATH, "foo_", "_my_lib_handle")
defer dynlib.unload_library(sym._my_lib_handle)
- fmt.printf("(Initial DLL Load) ok: %v. %v symbols loaded from lib.dll (%p).\n", ok, count, sym._my_lib_handle)
+ fmt.printf("(Initial DLL Load) ok: %v. %v symbols loaded from " + LIB_PATH + " (%p).\n", ok, count, sym._my_lib_handle)
if count > 0 {
fmt.println("42 + 42 =", sym.add(42, 42))
@@ -34,12 +36,12 @@ main :: proc() {
fmt.println("hellope =", sym.hellope^)
}
- count, ok = dynlib.initialize_symbols(&sym, "lib.dll", "foo_", "_my_lib_handle")
- fmt.printf("(DLL Reload) ok: %v. %v symbols loaded from lib.dll (%p).\n", ok, count, sym._my_lib_handle)
+ count, ok = dynlib.initialize_symbols(&sym, LIB_PATH, "foo_", "_my_lib_handle")
+ fmt.printf("(DLL Reload) ok: %v. %v symbols loaded from " + LIB_PATH + " (%p).\n", ok, count, sym._my_lib_handle)
if count > 0 {
fmt.println("42 + 42 =", sym.add(42, 42))
fmt.println("84 - 13 =", sym.sub(84, 13))
fmt.println("hellope =", sym.hellope^)
}
-} \ No newline at end of file
+}
diff --git a/core/dynlib/lib.odin b/core/dynlib/lib.odin
index 84675a560..cd9eed5f8 100644
--- a/core/dynlib/lib.odin
+++ b/core/dynlib/lib.odin
@@ -13,6 +13,11 @@ A handle to a dynamically loaded library.
Library :: distinct rawptr
/*
+The file extension for dynamic libraries on the target OS.
+*/
+LIBRARY_FILE_EXTENSION :: _LIBRARY_FILE_EXTENSION
+
+/*
Loads a dynamic library from the filesystem. The paramater `global_symbols` makes the symbols in the loaded
library available to resolve references in subsequently loaded libraries.
@@ -123,31 +128,36 @@ initialize_symbols :: proc(
) -> (count: int = -1, ok: bool = false) where intrinsics.type_is_struct(T) {
assert(symbol_table != nil)
- handle := load_library(library_path) or_return
-
- // Buffer to concatenate the prefix + symbol name.
- prefixed_symbol_buf: [2048]u8 = ---
-
- count = 0
+ // First, (re)load the library.
+ handle: Library
for field in reflect.struct_fields_zipped(T) {
- // Calculate address of struct member
- field_ptr := rawptr(uintptr(symbol_table) + field.offset)
-
- // If we've come across the struct member for the handle, store it and continue scanning for other symbols.
if field.name == handle_field_name {
+ field_ptr := rawptr(uintptr(symbol_table) + field.offset)
+
// We appear to be hot reloading. Unload previous incarnation of the library.
if old_handle := (^Library)(field_ptr)^; old_handle != nil {
unload_library(old_handle) or_return
}
+
+ handle = load_library(library_path) or_return
(^Library)(field_ptr)^ = handle
- continue
+ break
}
+ }
+
+ // Buffer to concatenate the prefix + symbol name.
+ prefixed_symbol_buf: [2048]u8 = ---
- // We're not the library handle, so the field needs to be a pointer type, be it a procedure pointer or an exported global.
- if !(reflect.is_procedure(field.type) || reflect.is_pointer(field.type)) {
+ count = 0
+ for field in reflect.struct_fields_zipped(T) {
+ // If we're not the library handle, the field needs to be a pointer type, be it a procedure pointer or an exported global.
+ if field.name == handle_field_name || !(reflect.is_procedure(field.type) || reflect.is_pointer(field.type)) {
continue
}
+ // Calculate address of struct member
+ field_ptr := rawptr(uintptr(symbol_table) + field.offset)
+
// Let's look up or construct the symbol name to find in the library
prefixed_name: string
diff --git a/core/dynlib/lib_js.odin b/core/dynlib/lib_js.odin
index b99143ba0..99f486dd0 100644
--- a/core/dynlib/lib_js.odin
+++ b/core/dynlib/lib_js.odin
@@ -4,6 +4,8 @@ package dynlib
import "base:runtime"
+_LIBRARY_FILE_EXTENSION :: ""
+
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
return nil, false
}
diff --git a/core/dynlib/lib_unix.odin b/core/dynlib/lib_unix.odin
index 337bf496d..50ab1acc8 100644
--- a/core/dynlib/lib_unix.odin
+++ b/core/dynlib/lib_unix.odin
@@ -7,6 +7,8 @@ import "base:runtime"
import "core:strings"
import "core:sys/posix"
+_LIBRARY_FILE_EXTENSION :: "dylib" when ODIN_OS == .Darwin else "so"
+
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
flags := posix.RTLD_Flags{.NOW}
if global_symbols {
diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin
index 928a1510d..05cd2cb3c 100644
--- a/core/dynlib/lib_windows.odin
+++ b/core/dynlib/lib_windows.odin
@@ -8,6 +8,8 @@ import win32 "core:sys/windows"
import "core:strings"
import "core:reflect"
+_LIBRARY_FILE_EXTENSION :: "dll"
+
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
wide_path := win32.utf8_to_wstring(path, allocator)