diff options
author | George Marques <george@gmarqu.es> | 2023-08-02 17:14:03 -0300 |
---|---|---|
committer | George Marques <george@gmarqu.es> | 2023-08-11 10:44:23 -0300 |
commit | cff69b0612a4bfc002bd40080829c66e1bb463b7 (patch) | |
tree | e2f3ffdc8eb1d959470499aed38ebec1f478364d | |
parent | 4714e95896c8db02616ea6ec7f9aff92dec1cae4 (diff) | |
download | redot-engine-cff69b0612a4bfc002bd40080829c66e1bb463b7.tar.gz |
GDExtension: Copy DLL to a temp file before opening
This is done only in the editor and only on Windows, to avoid a file
lock that prevents the original library being updated (e.g. by a
compiler).
When the game runs it will load the original DLL and pick up any
changes, only the editor will stay with the copy (until it is restarted
and create a new copy).
The copy is done in place by prepending a `~` to the original file name,
so dependencies that are loaded with a relative file path still work.
When the library is unloaded the copy file is deleted. The copy is also
marked as hidden to not show up in explorer.
-rw-r--r-- | core/extension/gdextension.cpp | 41 | ||||
-rw-r--r-- | core/extension/gdextension.h | 7 | ||||
-rw-r--r-- | main/main.cpp | 7 |
3 files changed, 54 insertions, 1 deletions
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 67b55db3db..c3f84c2a15 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -485,6 +485,13 @@ void GDExtension::close_library() { ERR_FAIL_COND(library == nullptr); OS::get_singleton()->close_dynamic_library(library); +#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED) + // Delete temporary copy of library if it exists. + if (!temp_lib_path.is_empty() && Engine::get_singleton()->is_editor_hint()) { + DirAccess::remove_absolute(temp_lib_path); + } +#endif + library = nullptr; } @@ -640,6 +647,40 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String Ref<GDExtension> lib; lib.instantiate(); String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path); + +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + // If running on the editor on Windows, we copy the library and open the copy. + // This is so the original file isn't locked and can be updated by a compiler. + if (Engine::get_singleton()->is_editor_hint()) { + if (!FileAccess::exists(abs_path)) { + if (r_error) { + *r_error = ERR_FILE_NOT_FOUND; + } + ERR_PRINT("GDExtension library not found: " + library_path); + return Ref<Resource>(); + } + + // Copy the file to the same directory as the original with a prefix in the name. + // This is so relative path to dependencies are satisfied. + String copy_path = abs_path.get_base_dir().path_join("~" + abs_path.get_file()); + + Error copy_err = DirAccess::copy_absolute(abs_path, copy_path); + if (copy_err) { + if (r_error) { + *r_error = ERR_CANT_CREATE; + } + ERR_PRINT("Error copying GDExtension library: " + library_path); + return Ref<Resource>(); + } + FileAccess::set_hidden_attribute(copy_path, true); + + // Save the copied path so it can be deleted later. + lib->set_temp_library_path(copy_path); + + // Use the copy to open the library. + abs_path = copy_path; + } +#endif err = lib->open_library(abs_path, entry_symbol); if (r_error) { diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index b935f8706f..5a4dd3d5f5 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -43,6 +43,9 @@ class GDExtension : public Resource { void *library = nullptr; // pointer if valid, String library_path; +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + String temp_lib_path; +#endif struct Extension { ObjectGDExtension gdextension; @@ -76,6 +79,10 @@ public: Error open_library(const String &p_path, const String &p_entry_symbol); void close_library(); +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + void set_temp_library_path(const String &p_path) { temp_lib_path = p_path; } +#endif + enum InitializationLevel { INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE, INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS, diff --git a/main/main.cpp b/main/main.cpp index 220afda5de..1c047371e5 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1540,6 +1540,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } } +#ifdef TOOLS_ENABLED + if (editor) { + Engine::get_singleton()->set_editor_hint(true); + } +#endif + // Initialize user data dir. OS::get_singleton()->ensure_user_data_dir(); @@ -1567,7 +1573,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #ifdef TOOLS_ENABLED if (editor) { packed_data->set_disabled(true); - Engine::get_singleton()->set_editor_hint(true); main_args.push_back("--editor"); if (!init_windowed) { init_maximized = true; |