From b1465d6af088abd9771cd8a0c087d4e8b141c884 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Fri, 14 Nov 2025 15:56:11 -0500 Subject: [PATCH] iOS: Fix loading of xcframework dynamic libraries. The logic used to determine whether to invoke the in-memory registration or to delegate the loading of a library is incorrect for xcframework packages - as these can contain either static or dynamic libraries. This change instead lets the operating system handle the library request, and if it fails, it attempts to load from the internal registry. With this change, xcframeworks containing dynamic libraries work without workarounds on iOS. With an additional fallback case courtesy of @bruvzg This fixes https://github.com/godotengine/godot/issues/112783 --- core/extension/gdextension_library_loader.cpp | 10 ++++++---- core/extension/gdextension_library_loader.h | 2 -- drivers/apple_embedded/os_apple_embedded.mm | 15 ++++++++++++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/core/extension/gdextension_library_loader.cpp b/core/extension/gdextension_library_loader.cpp index 0841443eba6..8db6ef390ef 100644 --- a/core/extension/gdextension_library_loader.cpp +++ b/core/extension/gdextension_library_loader.cpp @@ -195,9 +195,13 @@ Error GDExtensionLibraryLoader::open_library(const String &p_path) { &abs_dependencies_paths, // library_dependencies }; - err = OS::get_singleton()->open_dynamic_library(is_static_library ? String() : abs_path, library, &data); + // Apple has a complex lookup system which goes beyond looking up the filename, so we try that first. + err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data); if (err != OK) { - return err; + err = OS::get_singleton()->open_dynamic_library(String(), library, &data); + if (err != OK) { + return err; + } } return OK; @@ -361,8 +365,6 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) { return ERR_FILE_NOT_FOUND; } - is_static_library = library_path.ends_with(".a") || library_path.ends_with(".xcframework"); - if (!library_path.is_resource_file() && !library_path.is_absolute_path()) { library_path = p_path.get_base_dir().path_join(library_path); } diff --git a/core/extension/gdextension_library_loader.h b/core/extension/gdextension_library_loader.h index 75ad0ebedf7..d416c83da79 100644 --- a/core/extension/gdextension_library_loader.h +++ b/core/extension/gdextension_library_loader.h @@ -49,8 +49,6 @@ private: String library_path; String entry_symbol; - bool is_static_library = false; - #ifdef TOOLS_ENABLED bool is_reloadable = false; #endif diff --git a/drivers/apple_embedded/os_apple_embedded.mm b/drivers/apple_embedded/os_apple_embedded.mm index eab16ead8bb..aac51febfdc 100644 --- a/drivers/apple_embedded/os_apple_embedded.mm +++ b/drivers/apple_embedded/os_apple_embedded.mm @@ -279,6 +279,11 @@ Error OS_AppleEmbedded::open_dynamic_library(const String &p_path, void *&p_libr path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file().get_basename() + ".framework")); } + if (!FileAccess::exists(path)) { + // Load .dylib from within the executable path. + path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file().get_basename() + ".dylib")); + } + if (!FileAccess::exists(path)) { // Load .dylib or framework from a standard iOS location. path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file())); @@ -289,8 +294,16 @@ Error OS_AppleEmbedded::open_dynamic_library(const String &p_path, void *&p_libr path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file().get_basename() + ".framework")); } - ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); + if (!FileAccess::exists(path)) { + // Load .dylib from a standard iOS location. + path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file().get_basename() + ".dylib")); + } + if (!FileAccess::exists(path) && (p_path.ends_with(".a") || p_path.ends_with(".xcframework"))) { + path = String(); // Try loading static library. + } else { + ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND); + } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));