diff options
author | Gilles Roudière <gilles.roudiere@gmail.com> | 2022-10-26 18:23:09 +0200 |
---|---|---|
committer | Gilles Roudière <gilles.roudiere@gmail.com> | 2022-12-01 18:20:40 +0100 |
commit | fa4143cdeba7c01454190ef90717b73fa6f5722f (patch) | |
tree | 0126adf81b5603ab46a7384bfae8e83c67b9ad67 | |
parent | 36bcb8256543fdad71d3f6c7179584ff2591cac6 (diff) |
Allow specifying a prefix to automatically detect library files for gdextension exports
-rw-r--r-- | core/extension/native_extension.cpp | 130 | ||||
-rw-r--r-- | core/extension/native_extension.h | 4 | ||||
-rw-r--r-- | core/os/os.cpp | 18 | ||||
-rw-r--r-- | editor/export/editor_export_platform.cpp | 5 | ||||
-rw-r--r-- | editor/export/editor_export_platform_pc.cpp | 4 | ||||
-rw-r--r-- | editor/plugins/gdextension_export_plugin.h | 93 | ||||
-rw-r--r-- | editor/project_settings_editor.cpp | 6 | ||||
-rw-r--r-- | tests/core/os/test_os.h | 12 |
8 files changed, 174 insertions, 98 deletions
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<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) { + // First, check the explicit libraries. + if (p_config->has_section("libraries")) { + List<String> libraries; + p_config->get_section_keys("libraries", &libraries); + + // Iterate the libraries, finding the best matching tags. + String best_library_path; + Vector<String> best_library_tags; + for (const String &E : libraries) { + Vector<String> 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<DirAccess> 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<String> 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<String> 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<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St String entry_symbol = config->get_value("configuration", "entry_symbol"); - List<String> libraries; - - config->get_section_keys("libraries", &libraries); - - String library_path; - - for (const String &E : libraries) { - Vector<String> 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 <functional> + #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<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr); Error open_library(const String &p_path, const String &p_entry_symbol); void close_library(); diff --git a/core/os/os.cpp b/core/os/os.cpp index bbb2a94fe7..055385579f 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -353,20 +353,26 @@ bool OS::has_feature(const String &p_feature) { if (p_feature == "debug") { return true; } +#endif // DEBUG_ENABLED + +#ifdef TOOLS_ENABLED + if (p_feature == "editor") { + return true; + } #else - if (p_feature == "release") { + if (p_feature == "template") { return true; } -#endif -#ifdef TOOLS_ENABLED - if (p_feature == "editor") { +#ifdef DEBUG_ENABLED + if (p_feature == "template_debug") { return true; } #else - if (p_feature == "standalone") { + if (p_feature == "template_release" || p_feature == "release") { return true; } -#endif +#endif // DEBUG_ENABLED +#endif // TOOLS_ENABLED if (sizeof(void *) == 8 && p_feature == "64") { return true; diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 7c5c7da2ef..9819843fd7 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -442,10 +442,11 @@ HashSet<String> EditorExportPlatform::get_features(const Ref<EditorExportPreset> result.insert(E); } + result.insert("template"); if (p_debug) { - result.insert("debug"); + result.insert("template_debug"); } else { - result.insert("release"); + result.insert("template_release"); } if (!p_preset->get_custom_features().is_empty()) { diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp index 9de2f94900..5345346c48 100644 --- a/editor/export/editor_export_platform_pc.cpp +++ b/editor/export/editor_export_platform_pc.cpp @@ -81,8 +81,8 @@ bool EditorExportPlatformPC::has_valid_export_configuration(const Ref<EditorExpo // Look for export templates (first official, and if defined custom templates). String arch = p_preset->get("binary_format/architecture"); - bool dvalid = exists_export_template(get_template_file_name("debug", arch), &err); - bool rvalid = exists_export_template(get_template_file_name("release", arch), &err); + bool dvalid = exists_export_template(get_template_file_name("template_debug", arch), &err); + bool rvalid = exists_export_template(get_template_file_name("template_release", arch), &err); if (p_preset->get("custom_template/debug") != "") { dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h index 54f7ece1ee..d62691c76d 100644 --- a/editor/plugins/gdextension_export_plugin.h +++ b/editor/plugins/gdextension_export_plugin.h @@ -54,57 +54,36 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p String entry_symbol = config->get_value("configuration", "entry_symbol"); - List<String> libraries; - - config->get_section_keys("libraries", &libraries); - - bool could_export = false; - for (const String &E : libraries) { - Vector<String> tags = E.split("."); - bool all_tags_met = true; - for (int i = 0; i < tags.size(); i++) { - String tag = tags[i].strip_edges(); - if (!p_features.has(tag)) { - all_tags_met = false; - break; - } - } - - if (all_tags_met) { - String library_path = config->get_value("libraries", E); - if (library_path.is_relative_path()) { - library_path = p_path.get_base_dir().path_join(library_path); - } - add_shared_object(library_path, tags); - - if (p_features.has("iOS") && (library_path.ends_with(".a") || library_path.ends_with(".xcframework"))) { - String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n" - "extern void add_ios_init_callback(void (*cb)());\n" - "\n" - "extern \"C\" void $ENTRY();\n" - "void $ENTRY_init() {\n" - " if (&$ENTRY) register_dynamic_symbol((char *)\"$ENTRY\", (void *)$ENTRY);\n" - "}\n" - "struct $ENTRY_struct {\n" - " $ENTRY_struct() {\n" - " add_ios_init_callback($ENTRY_init);\n" - " }\n" - "};\n" - "$ENTRY_struct $ENTRY_struct_instance;\n\n"; - additional_code = additional_code.replace("$ENTRY", entry_symbol); - add_ios_cpp_code(additional_code); - - String linker_flags = "-Wl,-U,_" + entry_symbol; - add_ios_linker_flags(linker_flags); - } - could_export = true; - break; + PackedStringArray tags; + String library_path = NativeExtension::find_extension_library( + p_path, config, [p_features](String p_feature) { return p_features.has(p_feature); }, &tags); + if (!library_path.is_empty()) { + add_shared_object(library_path, tags); + + if (p_features.has("iOS") && (library_path.ends_with(".a") || library_path.ends_with(".xcframework"))) { + String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n" + "extern void add_ios_init_callback(void (*cb)());\n" + "\n" + "extern \"C\" void $ENTRY();\n" + "void $ENTRY_init() {\n" + " if (&$ENTRY) register_dynamic_symbol((char *)\"$ENTRY\", (void *)$ENTRY);\n" + "}\n" + "struct $ENTRY_struct {\n" + " $ENTRY_struct() {\n" + " add_ios_init_callback($ENTRY_init);\n" + " }\n" + "};\n" + "$ENTRY_struct $ENTRY_struct_instance;\n\n"; + additional_code = additional_code.replace("$ENTRY", entry_symbol); + add_ios_cpp_code(additional_code); + + String linker_flags = "-Wl,-U,_" + entry_symbol; + add_ios_linker_flags(linker_flags); } - } - if (!could_export) { - Vector<String> tags; + } else { + Vector<String> features_vector; for (const String &E : p_features) { - tags.append(E); + features_vector.append(E); } ERR_FAIL_MSG(vformat("No suitable library found. The libraries' tags referred to an invalid feature flag. Possible feature flags for your platform: %s", p_path, String(", ").join(tags))); } @@ -114,11 +93,11 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p config->get_section_keys("dependencies", &dependencies); } - for (const String &E : libraries) { - Vector<String> tags = E.split("."); + for (const String &E : dependencies) { + Vector<String> dependency_tags = E.split("."); bool all_tags_met = true; - for (int i = 0; i < tags.size(); i++) { - String tag = tags[i].strip_edges(); + for (int i = 0; i < dependency_tags.size(); i++) { + String tag = dependency_tags[i].strip_edges(); if (!p_features.has(tag)) { all_tags_met = false; break; @@ -128,12 +107,12 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p if (all_tags_met) { Dictionary dependency = config->get_value("dependencies", E); for (const Variant *key = dependency.next(nullptr); key; key = dependency.next(key)) { - String library_path = *key; + String dependency_path = *key; String target_path = dependency[*key]; - if (library_path.is_relative_path()) { - library_path = p_path.get_base_dir().path_join(library_path); + if (dependency_path.is_relative_path()) { + dependency_path = p_path.get_base_dir().path_join(dependency_path); } - add_shared_object(library_path, tags, target_path); + add_shared_object(dependency_path, dependency_tags, target_path); } break; } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 28111bed58..1e917e6b3d 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -274,10 +274,12 @@ void ProjectSettingsEditor::_add_feature_overrides() { presets.insert("s3tc"); presets.insert("etc"); presets.insert("etc2"); + presets.insert("editor"); + presets.insert("template_debug"); + presets.insert("template_release"); presets.insert("debug"); presets.insert("release"); - presets.insert("editor"); - presets.insert("standalone"); + presets.insert("template"); presets.insert("32"); presets.insert("64"); presets.insert("movie"); diff --git a/tests/core/os/test_os.h b/tests/core/os/test_os.h index c46da5e156..086f0b9b0c 100644 --- a/tests/core/os/test_os.h +++ b/tests/core/os/test_os.h @@ -97,14 +97,14 @@ TEST_CASE("[OS] Feature tags") { OS::get_singleton()->has_feature("editor"), "The binary has the \"editor\" feature tag."); CHECK_MESSAGE( - !OS::get_singleton()->has_feature("standalone"), - "The binary does not have the \"standalone\" feature tag."); + !OS::get_singleton()->has_feature("template"), + "The binary does not have the \"template\" feature tag."); CHECK_MESSAGE( - OS::get_singleton()->has_feature("debug"), - "The binary has the \"debug\" feature tag."); + !OS::get_singleton()->has_feature("template_debug"), + "The binary does not have the \"template_debug\" feature tag."); CHECK_MESSAGE( - !OS::get_singleton()->has_feature("release"), - "The binary does not have the \"release\" feature tag."); + !OS::get_singleton()->has_feature("template_release"), + "The binary does not have the \"template_release\" feature tag."); } TEST_CASE("[OS] Process ID") { |