Ver código fonte

Merge pull request #3116 from Kelimion/hot_reload

Add hot reload support to `dynlib.initialize_symbols`
Jeroen van Rijn 1 ano atrás
pai
commit
2071d7ba84
2 arquivos alterados com 20 adições e 3 exclusões
  1. 10 1
      core/dynlib/example/example.odin
  2. 10 2
      core/dynlib/lib.odin

+ 10 - 1
core/dynlib/example/example.odin

@@ -26,7 +26,16 @@ main :: proc() {
 	// 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")
 	defer dynlib.unload_library(sym._my_lib_handle)
-	fmt.printf("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.dll (%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^)
+	}
+
+	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)
 
 	if count > 0 {
 		fmt.println("42 + 42 =", sym.add(42, 42))

+ 10 - 2
core/dynlib/lib.odin

@@ -115,17 +115,19 @@ Optionally also takes the struct member to assign the library handle to, `__hand
 
 This allows using one struct to hold library handles and symbol pointers for more than 1 dynamic library.
 
+Loading the same library twice unloads the previous incarnation, allowing for straightforward hot reload support.
+
 Returns:
 * `-1, false` if the library could not be loaded.
 * The number of symbols assigned on success. `ok` = true if `count` > 0
 
 See doc.odin for an example.
 */
-initialize_symbols :: proc(symbol_table: ^$T, library_name: string, symbol_prefix := "", handle_field_name := "__handle") -> (count: int, ok: bool) where intrinsics.type_is_struct(T) {
+initialize_symbols :: proc(symbol_table: ^$T, library_path: string, symbol_prefix := "", handle_field_name := "__handle") -> (count: int, ok: bool) where intrinsics.type_is_struct(T) {
 	assert(symbol_table != nil)
 	handle: Library
 
-	if handle, ok = load_library(library_name); !ok {
+	if handle, ok = load_library(library_path); !ok {
 		return -1, false
 	}
 
@@ -143,6 +145,12 @@ initialize_symbols :: proc(symbol_table: ^$T, library_name: string, symbol_prefi
 
 		// 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 {
+			// We appear to be hot reloading. Unload previous incarnation of the library.
+			if old_handle := (^Library)(field_ptr)^; old_handle != nil {
+				if ok = unload_library(old_handle); !ok {
+					return count, ok
+				}
+			}
 			(^Library)(field_ptr)^ = handle
 			continue
 		}