From 58898a54844dc156d1dd0468e26810f4cfaf0465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Thu, 18 Jan 2024 13:54:25 +0100 Subject: [PATCH] Linux: Add support for arm64 and arm32 export templates This is done in a hacky way, mostly to keep it simple and avoid having to do a refactoring of the `EditorExportPlatform` interface. Only Windows and Linux use `EditorExportPlatformPC`, and thus to handle the new architectures for Linux, we simply do a few checks here and there with a couple new methods to register the export template names for Linux arm64 and arm32. For Godot 4.0, we did refactor everything to allow exporting binaries for different architectures cleanly. For 3.6, which is likely the last feature release for the 3.x branch, I tend to cut corners as these improvements will be shorter lived and thus new tech debt isn't as big a concern. --- editor/editor_export.cpp | 120 +++++++++++++++++++++++++++------ editor/editor_export.h | 8 +++ platform/x11/export/export.cpp | 18 +++-- 3 files changed, 121 insertions(+), 25 deletions(-) diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index fed58756c0a..5d59e9a8a5d 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -69,6 +69,17 @@ bool EditorExportPreset::_set(const StringName &p_name, const Variant &p_value) } return true; } +#ifndef DISABLE_DEPRECATED + // Compatibility with new `binary_format/architecture` for Linux in 3.6+. + else if (p_name == "binary_format/64_bits" && values.has("binary_format/architecture")) { + values["binary_format/architecture"] = (bool)p_value ? "x86_64" : "x86_32"; + EditorExport::singleton->save_presets(); + if (update_visibility["binary_format/architecture"]) { + property_list_changed_notify(); + } + return true; + } +#endif return false; } @@ -1629,10 +1640,20 @@ void EditorExportPlatformPC::get_preset_features(const Ref & r_features->push_back("etc2"); } - if (p_preset->get("binary_format/64_bits")) { - r_features->push_back("64"); + if (get_os_name() == "X11") { + const String &arch = get_preset_arch(p_preset); + r_features->push_back(arch); + if (arch == "x86_64" || arch == "arm64") { + r_features->push_back("64"); + } else { + r_features->push_back("32"); + } } else { - r_features->push_back("32"); + if (p_preset->get("binary_format/64_bits")) { + r_features->push_back("64"); + } else { + r_features->push_back("32"); + } } } @@ -1641,7 +1662,15 @@ void EditorExportPlatformPC::get_export_options(List *r_options) { r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, ext_filter), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, ext_filter), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "binary_format/64_bits"), true)); + // Linux support to export to ARM architectures was added in 3.6. + // Given how late this arrived, we didn't refactor the whole export preset + // interface to support more per-platform flexibility, like done in 4.0, + // so instead we hack the few needed changes here with `get_os_name()` checks. + if (get_os_name() == "X11") { + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32"), "x86_64")); + } else { + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "binary_format/64_bits"), true)); + } r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "binary_format/embed_pck"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/bptc"), false)); @@ -1665,12 +1694,20 @@ Ref EditorExportPlatformPC::get_logo() const { bool EditorExportPlatformPC::has_valid_export_configuration(const Ref &p_preset, String &r_error, bool &r_missing_templates) const { String err; bool valid = false; + bool dvalid = false; + bool rvalid = false; // Look for export templates (first official, and if defined custom templates). - bool use64 = p_preset->get("binary_format/64_bits"); - bool dvalid = exists_export_template(use64 ? debug_file_64 : debug_file_32, &err); - bool rvalid = exists_export_template(use64 ? release_file_64 : release_file_32, &err); + if (get_os_name() == "X11") { + const String &arch = get_preset_arch(p_preset); + dvalid = exists_export_template(debug_files[arch], &err); + rvalid = exists_export_template(release_files[arch], &err); + } else { + bool use64 = p_preset->get("binary_format/64_bits"); + dvalid = exists_export_template(use64 ? debug_file_64 : debug_file_32, &err); + rvalid = exists_export_template(use64 ? release_file_64 : release_file_32, &err); + } if (p_preset->get("custom_template/debug") != "") { dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); @@ -1722,9 +1759,16 @@ bool EditorExportPlatform::can_export(const Ref &p_preset, S List EditorExportPlatformPC::get_binary_extensions(const Ref &p_preset) const { List list; for (Map::Element *E = extensions.front(); E; E = E->next()) { - if (p_preset->get(E->key())) { - list.push_back(extensions[E->key()]); - return list; + if (get_os_name() == "X11") { + if (get_preset_arch(p_preset) == E->key()) { + list.push_back(extensions[E->key()]); + return list; + } + } else { + if (p_preset->get(E->key())) { + list.push_back(extensions[E->key()]); + return list; + } } } @@ -1764,17 +1808,25 @@ Error EditorExportPlatformPC::prepare_template(const Ref &p_ template_path = template_path.strip_edges(); if (template_path == String()) { - if (p_preset->get("binary_format/64_bits")) { + if (get_os_name() == "X11") { if (p_debug) { - template_path = find_export_template(debug_file_64); + template_path = find_export_template(debug_files[get_preset_arch(p_preset)]); } else { - template_path = find_export_template(release_file_64); + template_path = find_export_template(release_files[get_preset_arch(p_preset)]); } } else { - if (p_debug) { - template_path = find_export_template(debug_file_32); + if (p_preset->get("binary_format/64_bits")) { + if (p_debug) { + template_path = find_export_template(debug_file_64); + } else { + template_path = find_export_template(release_file_64); + } } else { - template_path = find_export_template(release_file_32); + if (p_debug) { + template_path = find_export_template(debug_file_32); + } else { + template_path = find_export_template(release_file_32); + } } } } @@ -1808,9 +1860,18 @@ Error EditorExportPlatformPC::export_project_data(const Ref int64_t embedded_size; Error err = save_pack(p_preset, pck_path, &so_files, p_preset->get("binary_format/embed_pck"), &embedded_pos, &embedded_size); if (err == OK && p_preset->get("binary_format/embed_pck")) { - if (embedded_size >= 0x100000000 && !p_preset->get("binary_format/64_bits")) { - add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("On 32-bit exports the embedded PCK cannot be bigger than 4 GiB.")); - return ERR_INVALID_PARAMETER; + if (embedded_size >= 0x100000000) { + bool use64; + if (get_os_name() == "X11") { + const String &arch = get_preset_arch(p_preset); + use64 = (arch == "x86_64" || arch == "arm64"); + } else { + use64 = p_preset->get("binary_format/64_bits"); + } + if (!use64) { + add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("On 32-bit exports the embedded PCK cannot be bigger than 4 GiB.")); + return ERR_INVALID_PARAMETER; + } } err = fixup_embedded_pck(p_path, embedded_pos, embedded_size); @@ -1857,13 +1918,34 @@ void EditorExportPlatformPC::set_release_64(const String &p_file) { void EditorExportPlatformPC::set_release_32(const String &p_file) { release_file_32 = p_file; } + void EditorExportPlatformPC::set_debug_64(const String &p_file) { debug_file_64 = p_file; } + void EditorExportPlatformPC::set_debug_32(const String &p_file) { debug_file_32 = p_file; } +// For Linux only. +void EditorExportPlatformPC::set_release_files(const String &p_arch, const String &p_file) { + release_files[p_arch] = p_file; +} + +void EditorExportPlatformPC::set_debug_files(const String &p_arch, const String &p_file) { + debug_files[p_arch] = p_file; +} + +String EditorExportPlatformPC::get_preset_arch(const Ref &p_preset) const { + String arch = p_preset->get("binary_format/architecture"); + if (arch != "x86_64" && arch != "x86_32" && arch != "arm64" && arch != "arm32") { + ERR_PRINT(vformat("Invalid value \"%s\" for \"binary_format/architecture\" in export preset \"%s\". Defaulting to \"x86_64\".", + arch, p_preset->get_name())); + arch = "x86_64"; + } + return arch; +} + void EditorExportPlatformPC::add_platform_feature(const String &p_feature) { extra_features.insert(p_feature); } diff --git a/editor/editor_export.h b/editor/editor_export.h index 8af76e57cbf..2d7db5a4384 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -472,6 +472,9 @@ private: String release_file_64; String debug_file_32; String debug_file_64; + // For Linux only. + Map release_files; + Map debug_files; Set extra_features; @@ -508,6 +511,11 @@ public: void set_debug_64(const String &p_file); void set_debug_32(const String &p_file); + // For Linux only. + void set_release_files(const String &p_arch, const String &p_file); + void set_debug_files(const String &p_arch, const String &p_file); + String get_preset_arch(const Ref &p_preset) const; + void add_platform_feature(const String &p_feature); virtual void get_platform_features(List *r_features); virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features); diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp index dfb9db5064c..449cb066f7c 100644 --- a/platform/x11/export/export.cpp +++ b/platform/x11/export/export.cpp @@ -162,12 +162,18 @@ void register_x11_exporter() { logo->create_from_image(img); platform->set_logo(logo); platform->set_name("Linux/X11"); - platform->set_extension("x86"); - platform->set_extension("x86_64", "binary_format/64_bits"); - platform->set_release_32("linux_x11_32_release"); - platform->set_debug_32("linux_x11_32_debug"); - platform->set_release_64("linux_x11_64_release"); - platform->set_debug_64("linux_x11_64_debug"); + platform->set_extension("x86_64", "x86_64"); + platform->set_extension("x86", "x86_32"); + platform->set_extension("arm64", "arm64"); + platform->set_extension("arm32", "arm32"); + platform->set_release_files("x86_64", "linux_x11_64_release"); + platform->set_release_files("x86_32", "linux_x11_32_release"); + platform->set_release_files("arm64", "linux_x11_arm64_release"); + platform->set_release_files("arm32", "linux_x11_arm32_release"); + platform->set_debug_files("x86_64", "linux_x11_64_debug"); + platform->set_debug_files("x86_32", "linux_x11_32_debug"); + platform->set_debug_files("arm64", "linux_x11_arm64_debug"); + platform->set_debug_files("arm32", "linux_x11_arm32_debug"); platform->set_os_name("X11"); platform->set_chmod_flags(0755);