[iOS export] Automatically generate ARM64 simulator library from device library if it's missing.
This commit is contained in:
parent
71699e08c9
commit
501c15c5f5
|
@ -28,8 +28,8 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#ifndef MACOS_CODESIGN_H
|
#ifndef CODESIGN_H
|
||||||
#define MACOS_CODESIGN_H
|
#define CODESIGN_H
|
||||||
|
|
||||||
// macOS code signature creation utility.
|
// macOS code signature creation utility.
|
||||||
//
|
//
|
||||||
|
@ -364,4 +364,4 @@ public:
|
||||||
|
|
||||||
#endif // MODULE_REGEX_ENABLED
|
#endif // MODULE_REGEX_ENABLED
|
||||||
|
|
||||||
#endif // MACOS_CODESIGN_H
|
#endif // CODESIGN_H
|
|
@ -37,7 +37,7 @@ bool LipO::is_lipo(const String &p_path) {
|
||||||
return (magic == 0xbebafeca || magic == 0xcafebabe || magic == 0xbfbafeca || magic == 0xcafebabf);
|
return (magic == 0xbebafeca || magic == 0xcafebabe || magic == 0xbfbafeca || magic == 0xcafebabf);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_files) {
|
bool LipO::create_file(const String &p_output_path, const Vector<String> &p_files) {
|
||||||
close();
|
close();
|
||||||
|
|
||||||
fa = FileAccess::open(p_output_path, FileAccess::WRITE);
|
fa = FileAccess::open(p_output_path, FileAccess::WRITE);
|
||||||
|
@ -125,6 +125,100 @@ bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_f
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LipO::create_file(const String &p_output_path, const Vector<String> &p_files, const Vector<Vector2i> &p_cputypes) {
|
||||||
|
close();
|
||||||
|
|
||||||
|
fa = FileAccess::open(p_output_path, FileAccess::WRITE);
|
||||||
|
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_output_path));
|
||||||
|
ERR_FAIL_COND_V(p_files.size() != p_cputypes.size(), false);
|
||||||
|
|
||||||
|
uint64_t max_size = 0;
|
||||||
|
for (int i = 0; i < p_files.size(); i++) {
|
||||||
|
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
|
||||||
|
if (fb.is_null()) {
|
||||||
|
close();
|
||||||
|
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FatArch arch;
|
||||||
|
MachO mh;
|
||||||
|
if (MachO::is_macho(p_files[i]) && mh.open_file(p_files[i])) {
|
||||||
|
arch.cputype = mh.get_cputype();
|
||||||
|
arch.cpusubtype = mh.get_cpusubtype();
|
||||||
|
arch.offset = 0;
|
||||||
|
arch.size = mh.get_size();
|
||||||
|
arch.align = mh.get_align();
|
||||||
|
ERR_FAIL_V_MSG(arch.cputype != (uint32_t)p_cputypes[i].x || arch.cpusubtype != (uint32_t)p_cputypes[i].y, vformat("Mismatching MachO architecture: \"%s\".", p_files[i]));
|
||||||
|
} else {
|
||||||
|
arch.cputype = (uint32_t)p_cputypes[i].x;
|
||||||
|
arch.cpusubtype = (uint32_t)p_cputypes[i].y;
|
||||||
|
arch.offset = 0;
|
||||||
|
arch.size = fb->get_length();
|
||||||
|
arch.align = 0x03;
|
||||||
|
}
|
||||||
|
max_size += arch.size;
|
||||||
|
|
||||||
|
archs.push_back(arch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write header.
|
||||||
|
bool is_64 = (max_size >= std::numeric_limits<uint32_t>::max());
|
||||||
|
if (is_64) {
|
||||||
|
fa->store_32(0xbfbafeca);
|
||||||
|
} else {
|
||||||
|
fa->store_32(0xbebafeca);
|
||||||
|
}
|
||||||
|
fa->store_32(BSWAP32(archs.size()));
|
||||||
|
uint64_t offset = archs.size() * (is_64 ? 32 : 20) + 8;
|
||||||
|
for (int i = 0; i < archs.size(); i++) {
|
||||||
|
archs.write[i].offset = offset + PAD(offset, uint64_t(1) << archs[i].align);
|
||||||
|
if (is_64) {
|
||||||
|
fa->store_32(BSWAP32(archs[i].cputype));
|
||||||
|
fa->store_32(BSWAP32(archs[i].cpusubtype));
|
||||||
|
fa->store_64(BSWAP64(archs[i].offset));
|
||||||
|
fa->store_64(BSWAP64(archs[i].size));
|
||||||
|
fa->store_32(BSWAP32(archs[i].align));
|
||||||
|
fa->store_32(0);
|
||||||
|
} else {
|
||||||
|
fa->store_32(BSWAP32(archs[i].cputype));
|
||||||
|
fa->store_32(BSWAP32(archs[i].cpusubtype));
|
||||||
|
fa->store_32(BSWAP32(archs[i].offset));
|
||||||
|
fa->store_32(BSWAP32(archs[i].size));
|
||||||
|
fa->store_32(BSWAP32(archs[i].align));
|
||||||
|
}
|
||||||
|
offset = archs[i].offset + archs[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write files and padding.
|
||||||
|
for (int i = 0; i < archs.size(); i++) {
|
||||||
|
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
|
||||||
|
if (fb.is_null()) {
|
||||||
|
close();
|
||||||
|
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
|
||||||
|
}
|
||||||
|
uint64_t cur = fa->get_position();
|
||||||
|
for (uint64_t j = cur; j < archs[i].offset; j++) {
|
||||||
|
fa->store_8(0);
|
||||||
|
}
|
||||||
|
int pages = archs[i].size / 4096;
|
||||||
|
int remain = archs[i].size % 4096;
|
||||||
|
unsigned char step[4096];
|
||||||
|
for (int j = 0; j < pages; j++) {
|
||||||
|
uint64_t br = fb->get_buffer(step, 4096);
|
||||||
|
if (br > 0) {
|
||||||
|
fa->store_buffer(step, br);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint64_t br = fb->get_buffer(step, remain);
|
||||||
|
if (br > 0) {
|
||||||
|
fa->store_buffer(step, br);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool LipO::open_file(const String &p_path) {
|
bool LipO::open_file(const String &p_path) {
|
||||||
close();
|
close();
|
||||||
|
|
||||||
|
@ -198,6 +292,18 @@ int LipO::get_arch_count() const {
|
||||||
return archs.size();
|
return archs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t LipO::get_arch_cputype(int p_index) const {
|
||||||
|
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
|
||||||
|
ERR_FAIL_INDEX_V(p_index, archs.size(), 0);
|
||||||
|
return archs[p_index].cputype;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t LipO::get_arch_cpusubtype(int p_index) const {
|
||||||
|
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
|
||||||
|
ERR_FAIL_INDEX_V(p_index, archs.size(), 0);
|
||||||
|
return archs[p_index].cpusubtype;
|
||||||
|
}
|
||||||
|
|
||||||
bool LipO::extract_arch(int p_index, const String &p_path) {
|
bool LipO::extract_arch(int p_index, const String &p_path) {
|
||||||
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "LipO: File not opened.");
|
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "LipO: File not opened.");
|
||||||
ERR_FAIL_INDEX_V(p_index, archs.size(), false);
|
ERR_FAIL_INDEX_V(p_index, archs.size(), false);
|
|
@ -28,8 +28,8 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#ifndef MACOS_LIPO_H
|
#ifndef LIPO_H
|
||||||
#define MACOS_LIPO_H
|
#define LIPO_H
|
||||||
|
|
||||||
// Universal / Universal 2 fat binary file creator and extractor.
|
// Universal / Universal 2 fat binary file creator and extractor.
|
||||||
|
|
||||||
|
@ -57,10 +57,13 @@ class LipO : public RefCounted {
|
||||||
public:
|
public:
|
||||||
static bool is_lipo(const String &p_path);
|
static bool is_lipo(const String &p_path);
|
||||||
|
|
||||||
bool create_file(const String &p_output_path, const PackedStringArray &p_files);
|
bool create_file(const String &p_output_path, const Vector<String> &p_files);
|
||||||
|
bool create_file(const String &p_output_path, const Vector<String> &p_files, const Vector<Vector2i> &p_cputypes);
|
||||||
|
|
||||||
bool open_file(const String &p_path);
|
bool open_file(const String &p_path);
|
||||||
int get_arch_count() const;
|
int get_arch_count() const;
|
||||||
|
uint32_t get_arch_cputype(int p_index) const;
|
||||||
|
uint32_t get_arch_cpusubtype(int p_index) const;
|
||||||
bool extract_arch(int p_index, const String &p_path);
|
bool extract_arch(int p_index, const String &p_path);
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
@ -68,4 +71,4 @@ public:
|
||||||
~LipO();
|
~LipO();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MACOS_LIPO_H
|
#endif // LIPO_H
|
|
@ -28,8 +28,8 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#ifndef MACOS_MACHO_H
|
#ifndef MACHO_H
|
||||||
#define MACOS_MACHO_H
|
#define MACHO_H
|
||||||
|
|
||||||
// Mach-O binary object file format parser and editor.
|
// Mach-O binary object file format parser and editor.
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
#include "core/object/ref_counted.h"
|
#include "core/object/ref_counted.h"
|
||||||
|
|
||||||
class MachO : public RefCounted {
|
class MachO : public RefCounted {
|
||||||
|
public:
|
||||||
struct MachHeader {
|
struct MachHeader {
|
||||||
uint32_t cputype;
|
uint32_t cputype;
|
||||||
uint32_t cpusubtype;
|
uint32_t cpusubtype;
|
||||||
|
@ -98,6 +99,21 @@ class MachO : public RefCounted {
|
||||||
LC_LINKER_OPTIMIZATION_HINT = 0x0000002e,
|
LC_LINKER_OPTIMIZATION_HINT = 0x0000002e,
|
||||||
LC_VERSION_MIN_TVOS = 0x0000002f,
|
LC_VERSION_MIN_TVOS = 0x0000002f,
|
||||||
LC_VERSION_MIN_WATCHOS = 0x00000030,
|
LC_VERSION_MIN_WATCHOS = 0x00000030,
|
||||||
|
LC_BUILD_VERSION = 0x00000032,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PlatformID {
|
||||||
|
PLATFORM_UNKNOWN = 0,
|
||||||
|
PLATFORM_MACOS = 1,
|
||||||
|
PLATFORM_IOS = 2,
|
||||||
|
PLATFORM_TVOS = 3,
|
||||||
|
PLATFORM_WATCHOS = 4,
|
||||||
|
PLATFORM_BRIDGEOS = 5,
|
||||||
|
PLATFORM_MACCATALYST = 6,
|
||||||
|
PLATFORM_IOSSIMULATOR = 7,
|
||||||
|
PLATFORM_TVOSSIMULATOR = 8,
|
||||||
|
PLATFORM_WATCHOSSIMULATOR = 9,
|
||||||
|
PLATFORM_DRIVERKIT = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LoadCommandHeader {
|
struct LoadCommandHeader {
|
||||||
|
@ -158,6 +174,7 @@ class MachO : public RefCounted {
|
||||||
uint32_t reserved3;
|
uint32_t reserved3;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
Ref<FileAccess> fa;
|
Ref<FileAccess> fa;
|
||||||
bool swap = false;
|
bool swap = false;
|
||||||
|
|
||||||
|
@ -208,4 +225,4 @@ public:
|
||||||
bool set_signature_size(uint64_t p_size);
|
bool set_signature_size(uint64_t p_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MACOS_MACHO_H
|
#endif // MACHO_H
|
|
@ -41,6 +41,9 @@
|
||||||
<member name="application/export_project_only" type="bool" setter="" getter="">
|
<member name="application/export_project_only" type="bool" setter="" getter="">
|
||||||
If [code]true[/code], exports iOS project files without building an XCArchive or [code].ipa[/code] file. If [code]false[/code], exports iOS project files and builds an XCArchive and [code].ipa[/code] file at the same time. When combining Godot with Fastlane or other build pipelines, you may want to set this to [code]true[/code].
|
If [code]true[/code], exports iOS project files without building an XCArchive or [code].ipa[/code] file. If [code]false[/code], exports iOS project files and builds an XCArchive and [code].ipa[/code] file at the same time. When combining Godot with Fastlane or other build pipelines, you may want to set this to [code]true[/code].
|
||||||
</member>
|
</member>
|
||||||
|
<member name="application/generate_simulator_library_if_missing" type="bool" setter="" getter="">
|
||||||
|
If [code]true[/code], and ARM64 simulator library is missing from the export template, it is automatically generated from ARM64 device library.
|
||||||
|
</member>
|
||||||
<member name="application/icon_interpolation" type="int" setter="" getter="">
|
<member name="application/icon_interpolation" type="int" setter="" getter="">
|
||||||
Interpolation method used to resize application icon.
|
Interpolation method used to resize application icon.
|
||||||
</member>
|
</member>
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#include "editor/editor_paths.h"
|
#include "editor/editor_paths.h"
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
#include "editor/export/editor_export.h"
|
#include "editor/export/editor_export.h"
|
||||||
|
#include "editor/export/lipo.h"
|
||||||
|
#include "editor/export/macho.h"
|
||||||
#include "editor/import/resource_importer_texture_settings.h"
|
#include "editor/import/resource_importer_texture_settings.h"
|
||||||
#include "editor/plugins/script_editor_plugin.h"
|
#include "editor/plugins/script_editor_plugin.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
|
@ -248,7 +250,7 @@ bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPre
|
||||||
}
|
}
|
||||||
|
|
||||||
bool advanced_options_enabled = p_preset->are_advanced_options_enabled();
|
bool advanced_options_enabled = p_preset->are_advanced_options_enabled();
|
||||||
if (p_option.begins_with("privacy")) {
|
if (p_option.begins_with("privacy") || p_option == "application/generate_simulator_library_if_missing") {
|
||||||
return advanced_options_enabled;
|
return advanced_options_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,6 +290,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/delete_old_export_files_unconditionally"), false));
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/delete_old_export_files_unconditionally"), false));
|
||||||
|
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/generate_simulator_library_if_missing"), true));
|
||||||
|
|
||||||
Vector<PluginConfigIOS> found_plugins = get_plugins();
|
Vector<PluginConfigIOS> found_plugins = get_plugins();
|
||||||
for (int i = 0; i < found_plugins.size(); i++) {
|
for (int i = 0; i < found_plugins.size(); i++) {
|
||||||
|
@ -1150,6 +1153,167 @@ struct ExportLibsData {
|
||||||
String dest_dir;
|
String dest_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool EditorExportPlatformIOS::_archive_has_arm64(const String &p_path, uint32_t *r_cputype, uint32_t *r_cpusubtype) const {
|
||||||
|
bool has_arm64_image = false;
|
||||||
|
if (FileAccess::exists(p_path)) {
|
||||||
|
if (LipO::is_lipo(p_path)) {
|
||||||
|
// LipO.
|
||||||
|
Ref<LipO> lipo;
|
||||||
|
lipo.instantiate();
|
||||||
|
if (lipo->open_file(p_path)) {
|
||||||
|
for (int i = 0; i < lipo->get_arch_count(); i++) {
|
||||||
|
if (lipo->get_arch_cputype(i) == 0x100000c && lipo->get_arch_cpusubtype(i) == 0) {
|
||||||
|
has_arm64_image = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lipo->close();
|
||||||
|
} else {
|
||||||
|
// Single architecture archive.
|
||||||
|
Ref<FileAccess> sim_f = FileAccess::open(p_path, FileAccess::READ);
|
||||||
|
if (sim_f.is_valid()) {
|
||||||
|
char magic[9] = {};
|
||||||
|
sim_f->get_buffer((uint8_t *)&magic[0], 8);
|
||||||
|
if (String(magic) == String("!<arch>\n")) {
|
||||||
|
while (!sim_f->eof_reached()) {
|
||||||
|
// Read file metadata.
|
||||||
|
char name_short[17] = {};
|
||||||
|
char size_short[11] = {};
|
||||||
|
sim_f->get_buffer((uint8_t *)&name_short[0], 16);
|
||||||
|
sim_f->seek(sim_f->get_position() + 12 + 6 + 6 + 8); // Skip modification time, owner ID, group ID, file mode.
|
||||||
|
sim_f->get_buffer((uint8_t *)&size_short[0], 10);
|
||||||
|
sim_f->seek(sim_f->get_position() + 2); // Skip end marker.
|
||||||
|
|
||||||
|
int64_t file_size = String(size_short).to_int();
|
||||||
|
int64_t next_off = sim_f->get_position() + file_size;
|
||||||
|
|
||||||
|
String name = String(name_short); // Skip extended name.
|
||||||
|
if (name.is_empty() || file_size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (name.begins_with("#1/")) {
|
||||||
|
int64_t name_len = String(name_short).replace("#1/", "").to_int();
|
||||||
|
sim_f->seek(sim_f->get_position() + name_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file content.
|
||||||
|
uint32_t obj_magic = sim_f->get_32();
|
||||||
|
|
||||||
|
bool swap = (obj_magic == 0xcffaedfe || obj_magic == 0xcefaedfe);
|
||||||
|
if (obj_magic == 0xcefaedfe || obj_magic == 0xfeedface || obj_magic == 0xcffaedfe || obj_magic == 0xfeedfacf) {
|
||||||
|
uint32_t cputype = sim_f->get_32();
|
||||||
|
uint32_t cpusubtype = sim_f->get_32();
|
||||||
|
if (swap) {
|
||||||
|
cputype = BSWAP32(cputype);
|
||||||
|
cpusubtype = BSWAP32(cpusubtype);
|
||||||
|
}
|
||||||
|
if (r_cputype) {
|
||||||
|
*r_cputype = cputype;
|
||||||
|
}
|
||||||
|
if (r_cpusubtype) {
|
||||||
|
*r_cpusubtype = cpusubtype;
|
||||||
|
}
|
||||||
|
if (cputype == 0x100000c && cpusubtype == 0) {
|
||||||
|
has_arm64_image = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sim_f->seek(next_off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sim_f->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return has_arm64_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EditorExportPlatformIOS::_archive_convert_to_simulator(const String &p_path) const {
|
||||||
|
int commands_patched = 0;
|
||||||
|
Ref<FileAccess> sim_f = FileAccess::open(p_path, FileAccess::READ_WRITE);
|
||||||
|
if (sim_f.is_valid()) {
|
||||||
|
char magic[9] = {};
|
||||||
|
sim_f->get_buffer((uint8_t *)&magic[0], 8);
|
||||||
|
if (String(magic) == String("!<arch>\n")) {
|
||||||
|
while (!sim_f->eof_reached()) {
|
||||||
|
// Read file metadata.
|
||||||
|
char name_short[17] = {};
|
||||||
|
char size_short[11] = {};
|
||||||
|
sim_f->get_buffer((uint8_t *)&name_short[0], 16);
|
||||||
|
sim_f->seek(sim_f->get_position() + 12 + 6 + 6 + 8); // Skip modification time, owner ID, group ID, file mode.
|
||||||
|
sim_f->get_buffer((uint8_t *)&size_short[0], 10);
|
||||||
|
sim_f->seek(sim_f->get_position() + 2); // Skip end marker.
|
||||||
|
|
||||||
|
int64_t file_size = String(size_short).to_int();
|
||||||
|
int64_t next_off = sim_f->get_position() + file_size;
|
||||||
|
|
||||||
|
String name = String(name_short); // Skip extended name.
|
||||||
|
if (name.is_empty() || file_size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (name.begins_with("#1/")) {
|
||||||
|
int64_t name_len = String(name_short).replace("#1/", "").to_int();
|
||||||
|
sim_f->seek(sim_f->get_position() + name_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file content.
|
||||||
|
uint32_t obj_magic = sim_f->get_32();
|
||||||
|
|
||||||
|
bool swap = (obj_magic == 0xcffaedfe || obj_magic == 0xcefaedfe);
|
||||||
|
if (obj_magic == 0xcefaedfe || obj_magic == 0xfeedface || obj_magic == 0xcffaedfe || obj_magic == 0xfeedfacf) {
|
||||||
|
uint32_t cputype = sim_f->get_32();
|
||||||
|
uint32_t cpusubtype = sim_f->get_32();
|
||||||
|
uint32_t filetype = sim_f->get_32();
|
||||||
|
uint32_t ncmds = sim_f->get_32();
|
||||||
|
sim_f->get_32(); // Commands total size.
|
||||||
|
sim_f->get_32(); // Commands flags.
|
||||||
|
if (obj_magic == 0xcffaedfe || obj_magic == 0xfeedfacf) {
|
||||||
|
sim_f->get_32(); // Reserved, 64-bit only.
|
||||||
|
}
|
||||||
|
if (swap) {
|
||||||
|
ncmds = BSWAP32(ncmds);
|
||||||
|
cputype = BSWAP32(cputype);
|
||||||
|
cpusubtype = BSWAP32(cpusubtype);
|
||||||
|
filetype = BSWAP32(filetype);
|
||||||
|
}
|
||||||
|
if (cputype == 0x100000C && cpusubtype == 0 && filetype == 1) {
|
||||||
|
// ARM64, object file.
|
||||||
|
for (uint32_t i = 0; i < ncmds; i++) {
|
||||||
|
int64_t cmdofs = sim_f->get_position();
|
||||||
|
uint32_t cmdid = sim_f->get_32();
|
||||||
|
uint32_t cmdsize = sim_f->get_32();
|
||||||
|
if (swap) {
|
||||||
|
cmdid = BSWAP32(cmdid);
|
||||||
|
cmdsize = BSWAP32(cmdsize);
|
||||||
|
}
|
||||||
|
if (cmdid == MachO::LoadCommandID::LC_BUILD_VERSION) {
|
||||||
|
int64_t platform = sim_f->get_32();
|
||||||
|
if (swap) {
|
||||||
|
platform = BSWAP32(platform);
|
||||||
|
}
|
||||||
|
if (platform == MachO::PlatformID::PLATFORM_IOS) {
|
||||||
|
sim_f->seek(cmdofs + 4 + 4);
|
||||||
|
uint32_t new_id = MachO::PlatformID::PLATFORM_IOSSIMULATOR;
|
||||||
|
if (swap) {
|
||||||
|
new_id = BSWAP32(new_id);
|
||||||
|
}
|
||||||
|
sim_f->store_32(new_id);
|
||||||
|
commands_patched++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sim_f->seek(cmdofs + cmdsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sim_f->seek(next_off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sim_f->close();
|
||||||
|
}
|
||||||
|
return commands_patched;
|
||||||
|
}
|
||||||
|
|
||||||
void EditorExportPlatformIOS::_check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const {
|
void EditorExportPlatformIOS::_check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const {
|
||||||
Ref<PList> plist;
|
Ref<PList> plist;
|
||||||
plist.instantiate();
|
plist.instantiate();
|
||||||
|
@ -2146,7 +2310,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
|
||||||
ret = unzGoToNextFile(src_pkg_zip);
|
ret = unzGoToNextFile(src_pkg_zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we're done with our source zip */
|
// We're done with our source zip.
|
||||||
unzClose(src_pkg_zip);
|
unzClose(src_pkg_zip);
|
||||||
|
|
||||||
if (!found_library) {
|
if (!found_library) {
|
||||||
|
@ -2154,6 +2318,80 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check and generate missing ARM64 simulator library.
|
||||||
|
if (p_preset->get("application/generate_simulator_library_if_missing").operator bool()) {
|
||||||
|
String sim_lib_path = dest_dir + String(binary_name + ".xcframework").path_join("ios-arm64_x86_64-simulator").path_join("libgodot.a");
|
||||||
|
String dev_lib_path = dest_dir + String(binary_name + ".xcframework").path_join("ios-arm64").path_join("libgodot.a");
|
||||||
|
String tmp_lib_path = EditorPaths::get_singleton()->get_cache_dir().path_join(binary_name + "_lipo_");
|
||||||
|
uint32_t cputype = 0;
|
||||||
|
uint32_t cpusubtype = 0;
|
||||||
|
if (!_archive_has_arm64(sim_lib_path, &cputype, &cpusubtype) && _archive_has_arm64(dev_lib_path) && FileAccess::exists(dev_lib_path)) {
|
||||||
|
add_message(EXPORT_MESSAGE_INFO, TTR("Export"), TTR("ARM64 simulator library, generating from device library."));
|
||||||
|
|
||||||
|
Vector<String> tmp_lib_files;
|
||||||
|
Vector<Vector2i> tmp_lib_cputypes;
|
||||||
|
// Extract/copy simulator lib.
|
||||||
|
if (FileAccess::exists(sim_lib_path)) {
|
||||||
|
if (LipO::is_lipo(sim_lib_path)) {
|
||||||
|
Ref<LipO> lipo;
|
||||||
|
lipo.instantiate();
|
||||||
|
if (lipo->open_file(sim_lib_path)) {
|
||||||
|
for (int i = 0; i < lipo->get_arch_count(); i++) {
|
||||||
|
const String &f_name = tmp_lib_path + itos(tmp_lib_files.size());
|
||||||
|
lipo->extract_arch(i, f_name);
|
||||||
|
tmp_lib_files.push_back(f_name);
|
||||||
|
tmp_lib_cputypes.push_back(Vector2i(lipo->get_arch_cputype(i), lipo->get_arch_cpusubtype(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const String &f_name = tmp_lib_path + itos(tmp_lib_files.size());
|
||||||
|
tmp_app_path->copy(sim_lib_path, f_name);
|
||||||
|
tmp_lib_files.push_back(f_name);
|
||||||
|
tmp_lib_cputypes.push_back(Vector2i(cputype, cpusubtype));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Copy device lib.
|
||||||
|
if (LipO::is_lipo(dev_lib_path)) {
|
||||||
|
Ref<LipO> lipo;
|
||||||
|
lipo.instantiate();
|
||||||
|
if (lipo->open_file(dev_lib_path)) {
|
||||||
|
for (int i = 0; i < lipo->get_arch_count(); i++) {
|
||||||
|
if (lipo->get_arch_cputype(i) == 0x100000c && lipo->get_arch_cpusubtype(i) == 0) {
|
||||||
|
const String &f_name = tmp_lib_path + itos(tmp_lib_files.size());
|
||||||
|
lipo->extract_arch(i, f_name);
|
||||||
|
tmp_lib_files.push_back(f_name);
|
||||||
|
tmp_lib_cputypes.push_back(Vector2i(0x100000c, 0)); // ARM64.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const String &f_name = tmp_lib_path + itos(tmp_lib_files.size());
|
||||||
|
tmp_app_path->copy(dev_lib_path, f_name);
|
||||||
|
tmp_lib_files.push_back(f_name);
|
||||||
|
tmp_lib_cputypes.push_back(Vector2i(0x100000c, 0)); // ARM64.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch device lib.
|
||||||
|
int patch_count = _archive_convert_to_simulator(tmp_lib_path + itos(tmp_lib_files.size() - 1));
|
||||||
|
if (patch_count == 0) {
|
||||||
|
add_message(EXPORT_MESSAGE_WARNING, TTR("Export"), TTR("Unable to generate ARM64 simulator library."));
|
||||||
|
} else {
|
||||||
|
// Repack.
|
||||||
|
Ref<LipO> lipo;
|
||||||
|
lipo.instantiate();
|
||||||
|
lipo->create_file(sim_lib_path, tmp_lib_files, tmp_lib_cputypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup.
|
||||||
|
for (const String &E : tmp_lib_files) {
|
||||||
|
tmp_app_path->remove(E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate translations files.
|
||||||
|
|
||||||
Dictionary appnames = GLOBAL_GET("application/config/name_localized");
|
Dictionary appnames = GLOBAL_GET("application/config/name_localized");
|
||||||
Dictionary camera_usage_descriptions = p_preset->get("privacy/camera_usage_description_localized");
|
Dictionary camera_usage_descriptions = p_preset->get("privacy/camera_usage_description_localized");
|
||||||
Dictionary microphone_usage_descriptions = p_preset->get("privacy/microphone_usage_description_localized");
|
Dictionary microphone_usage_descriptions = p_preset->get("privacy/microphone_usage_description_localized");
|
||||||
|
|
|
@ -135,6 +135,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
|
||||||
Vector<ExportArchitecture> _get_supported_architectures() const;
|
Vector<ExportArchitecture> _get_supported_architectures() const;
|
||||||
Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const;
|
Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const;
|
||||||
|
|
||||||
|
bool _archive_has_arm64(const String &p_path, uint32_t *r_cputype = nullptr, uint32_t *r_cpusubtype = nullptr) const;
|
||||||
|
int _archive_convert_to_simulator(const String &p_path) const;
|
||||||
void _check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const;
|
void _check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const;
|
||||||
Error _convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const;
|
Error _convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const;
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,7 @@
|
||||||
|
|
||||||
#include "export_plugin.h"
|
#include "export_plugin.h"
|
||||||
|
|
||||||
#include "codesign.h"
|
|
||||||
#include "lipo.h"
|
|
||||||
#include "logo_svg.gen.h"
|
#include "logo_svg.gen.h"
|
||||||
#include "macho.h"
|
|
||||||
#include "run_icon_svg.gen.h"
|
#include "run_icon_svg.gen.h"
|
||||||
|
|
||||||
#include "core/io/image_loader.h"
|
#include "core/io/image_loader.h"
|
||||||
|
@ -43,6 +40,9 @@
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "editor/editor_paths.h"
|
#include "editor/editor_paths.h"
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
|
#include "editor/export/codesign.h"
|
||||||
|
#include "editor/export/lipo.h"
|
||||||
|
#include "editor/export/macho.h"
|
||||||
#include "editor/import/resource_importer_texture_settings.h"
|
#include "editor/import/resource_importer_texture_settings.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
#include "scene/resources/image_texture.h"
|
#include "scene/resources/image_texture.h"
|
||||||
|
|
Loading…
Reference in New Issue