Skip to content

Commit cff69b0

Browse files
committed
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.
1 parent 4714e95 commit cff69b0

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

core/extension/gdextension.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,13 @@ void GDExtension::close_library() {
485485
ERR_FAIL_COND(library == nullptr);
486486
OS::get_singleton()->close_dynamic_library(library);
487487

488+
#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED)
489+
// Delete temporary copy of library if it exists.
490+
if (!temp_lib_path.is_empty() && Engine::get_singleton()->is_editor_hint()) {
491+
DirAccess::remove_absolute(temp_lib_path);
492+
}
493+
#endif
494+
488495
library = nullptr;
489496
}
490497

@@ -640,6 +647,40 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
640647
Ref<GDExtension> lib;
641648
lib.instantiate();
642649
String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path);
650+
651+
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
652+
// If running on the editor on Windows, we copy the library and open the copy.
653+
// This is so the original file isn't locked and can be updated by a compiler.
654+
if (Engine::get_singleton()->is_editor_hint()) {
655+
if (!FileAccess::exists(abs_path)) {
656+
if (r_error) {
657+
*r_error = ERR_FILE_NOT_FOUND;
658+
}
659+
ERR_PRINT("GDExtension library not found: " + library_path);
660+
return Ref<Resource>();
661+
}
662+
663+
// Copy the file to the same directory as the original with a prefix in the name.
664+
// This is so relative path to dependencies are satisfied.
665+
String copy_path = abs_path.get_base_dir().path_join("~" + abs_path.get_file());
666+
667+
Error copy_err = DirAccess::copy_absolute(abs_path, copy_path);
668+
if (copy_err) {
669+
if (r_error) {
670+
*r_error = ERR_CANT_CREATE;
671+
}
672+
ERR_PRINT("Error copying GDExtension library: " + library_path);
673+
return Ref<Resource>();
674+
}
675+
FileAccess::set_hidden_attribute(copy_path, true);
676+
677+
// Save the copied path so it can be deleted later.
678+
lib->set_temp_library_path(copy_path);
679+
680+
// Use the copy to open the library.
681+
abs_path = copy_path;
682+
}
683+
#endif
643684
err = lib->open_library(abs_path, entry_symbol);
644685

645686
if (r_error) {

core/extension/gdextension.h

+7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class GDExtension : public Resource {
4343

4444
void *library = nullptr; // pointer if valid,
4545
String library_path;
46+
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
47+
String temp_lib_path;
48+
#endif
4649

4750
struct Extension {
4851
ObjectGDExtension gdextension;
@@ -76,6 +79,10 @@ class GDExtension : public Resource {
7679
Error open_library(const String &p_path, const String &p_entry_symbol);
7780
void close_library();
7881

82+
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
83+
void set_temp_library_path(const String &p_path) { temp_lib_path = p_path; }
84+
#endif
85+
7986
enum InitializationLevel {
8087
INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE,
8188
INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS,

main/main.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
15401540
}
15411541
}
15421542

1543+
#ifdef TOOLS_ENABLED
1544+
if (editor) {
1545+
Engine::get_singleton()->set_editor_hint(true);
1546+
}
1547+
#endif
1548+
15431549
// Initialize user data dir.
15441550
OS::get_singleton()->ensure_user_data_dir();
15451551

@@ -1567,7 +1573,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
15671573
#ifdef TOOLS_ENABLED
15681574
if (editor) {
15691575
packed_data->set_disabled(true);
1570-
Engine::get_singleton()->set_editor_hint(true);
15711576
main_args.push_back("--editor");
15721577
if (!init_windowed) {
15731578
init_maximized = true;

0 commit comments

Comments
 (0)