From fa4143cdeba7c01454190ef90717b73fa6f5722f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gilles=20Roudi=C3=A8re?= Date: Wed, 26 Oct 2022 18:23:09 +0200 Subject: Allow specifying a prefix to automatically detect library files for gdextension exports --- core/extension/native_extension.cpp | 130 +++++++++++++++++++++++++++++------- core/extension/native_extension.h | 4 ++ 2 files changed, 111 insertions(+), 23 deletions(-) (limited to 'core/extension') diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp index 83a2e80793..b494160329 100644 --- a/core/extension/native_extension.cpp +++ b/core/extension/native_extension.cpp @@ -30,7 +30,7 @@ #include "native_extension.h" #include "core/config/project_settings.h" -#include "core/io/config_file.h" +#include "core/io/dir_access.h" #include "core/object/class_db.h" #include "core/object/method_bind.h" #include "core/os/os.h" @@ -39,6 +39,111 @@ String NativeExtension::get_extension_list_config_file() { return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg"); } +String NativeExtension::find_extension_library(const String &p_path, Ref p_config, std::function p_has_feature, PackedStringArray *r_tags) { + // First, check the explicit libraries. + if (p_config->has_section("libraries")) { + List libraries; + p_config->get_section_keys("libraries", &libraries); + + // Iterate the libraries, finding the best matching tags. + String best_library_path; + Vector best_library_tags; + for (const String &E : libraries) { + Vector tags = E.split("."); + bool all_tags_met = true; + for (int i = 0; i < tags.size(); i++) { + String tag = tags[i].strip_edges(); + if (!p_has_feature(tag)) { + all_tags_met = false; + break; + } + } + + if (all_tags_met && tags.size() > best_library_tags.size()) { + best_library_path = p_config->get_value("libraries", E); + best_library_tags = tags; + } + } + + if (!best_library_path.is_empty()) { + if (best_library_path.is_relative_path()) { + best_library_path = p_path.get_base_dir().path_join(best_library_path); + } + if (r_tags != nullptr) { + r_tags->append_array(best_library_tags); + } + return best_library_path; + } + } + + // Second, try to autodetect + String autodetect_library_prefix; + if (p_config->has_section_key("configuration", "autodetect_library_prefix")) { + autodetect_library_prefix = p_config->get_value("configuration", "autodetect_library_prefix"); + } + if (!autodetect_library_prefix.is_empty()) { + String autodetect_path = autodetect_library_prefix; + if (autodetect_path.is_relative_path()) { + autodetect_path = p_path.get_base_dir().path_join(autodetect_path); + } + + // Find the folder and file parts of the prefix. + String folder; + String file_prefix; + if (DirAccess::dir_exists_absolute(autodetect_path)) { + folder = autodetect_path; + } else if (DirAccess::dir_exists_absolute(autodetect_path.get_base_dir())) { + folder = autodetect_path.get_base_dir(); + file_prefix = autodetect_path.get_file(); + } else { + ERR_FAIL_V_MSG(String(), vformat("Error in extension: %s. Could not find folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix)); + } + + // Open the folder. + Ref dir = DirAccess::open(folder); + ERR_FAIL_COND_V_MSG(!dir.is_valid(), String(), vformat("Error in extension: %s. Could not open folder for automatic detection of libraries files. autodetect_library_prefix=\"%s\"", p_path, autodetect_library_prefix)); + + // Iterate the files and check the prefixes, finding the best matching file. + String best_file; + Vector best_file_tags; + dir->list_dir_begin(); + String file_name = dir->_get_next(); + while (file_name != "") { + if (!dir->current_is_dir() && file_name.begins_with(file_prefix)) { + // Check if the files matches all requested feature tags. + String tags_str = file_name.trim_prefix(file_prefix); + tags_str = tags_str.trim_suffix(tags_str.get_extension()); + + Vector tags = tags_str.split(".", false); + bool all_tags_met = true; + for (int i = 0; i < tags.size(); i++) { + String tag = tags[i].strip_edges(); + if (!p_has_feature(tag)) { + all_tags_met = false; + break; + } + } + + // If all tags are found in the feature list, and we found more tags than before, use this file. + if (all_tags_met && tags.size() > best_file_tags.size()) { + best_file_tags = tags; + best_file = file_name; + } + } + file_name = dir->_get_next(); + } + + if (!best_file.is_empty()) { + String library_path = folder.path_join(best_file); + if (r_tags != nullptr) { + r_tags->append_array(best_file_tags); + } + return library_path; + } + } + return String(); +} + class NativeExtensionMethodBind : public MethodBind { GDNativeExtensionClassMethodCall call_func; GDNativeExtensionClassMethodPtrCall ptrcall_func; @@ -415,28 +520,7 @@ Ref NativeExtensionResourceLoader::load(const String &p_path, const St String entry_symbol = config->get_value("configuration", "entry_symbol"); - List libraries; - - config->get_section_keys("libraries", &libraries); - - String library_path; - - for (const String &E : libraries) { - Vector tags = E.split("."); - bool all_tags_met = true; - for (int i = 0; i < tags.size(); i++) { - String tag = tags[i].strip_edges(); - if (!OS::get_singleton()->has_feature(tag)) { - all_tags_met = false; - break; - } - } - - if (all_tags_met) { - library_path = config->get_value("libraries", E); - break; - } - } + String library_path = NativeExtension::find_extension_library(p_path, config, [](String p_feature) { return OS::get_singleton()->has_feature(p_feature); }); if (library_path.is_empty()) { if (r_error) { diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h index 70f6f9f039..4a1ccc27ca 100644 --- a/core/extension/native_extension.h +++ b/core/extension/native_extension.h @@ -31,7 +31,10 @@ #ifndef NATIVE_EXTENSION_H #define NATIVE_EXTENSION_H +#include + #include "core/extension/gdnative_interface.h" +#include "core/io/config_file.h" #include "core/io/resource_loader.h" #include "core/object/ref_counted.h" @@ -65,6 +68,7 @@ protected: public: static String get_extension_list_config_file(); + static String find_extension_library(const String &p_path, Ref p_config, std::function p_has_feature, PackedStringArray *r_tags = nullptr); Error open_library(const String &p_path, const String &p_entry_symbol); void close_library(); -- cgit v1.2.3