@@ -1256,6 +1256,167 @@ struct ExportLibsData {
12561256 String dest_dir;
12571257};
12581258
1259+ bool EditorExportPlatformIOS::_archive_has_arm64 (const String &p_path, uint32_t *r_cputype, uint32_t *r_cpusubtype) const {
1260+ bool has_arm64_image = false ;
1261+ if (FileAccess::exists (p_path)) {
1262+ if (LipO::is_lipo (p_path)) {
1263+ // LipO.
1264+ Ref<LipO> lipo;
1265+ lipo.instantiate ();
1266+ if (lipo->open_file (p_path)) {
1267+ for (int i = 0 ; i < lipo->get_arch_count (); i++) {
1268+ if (lipo->get_arch_cputype (i) == 0x100000c && lipo->get_arch_cpusubtype (i) == 0 ) {
1269+ has_arm64_image = true ;
1270+ break ;
1271+ }
1272+ }
1273+ }
1274+ lipo->close ();
1275+ } else {
1276+ // Single architecture archive.
1277+ Ref<FileAccess> sim_f = FileAccess::open (p_path, FileAccess::READ);
1278+ if (sim_f.is_valid ()) {
1279+ char magic[9 ] = {};
1280+ sim_f->get_buffer ((uint8_t *)&magic[0 ], 8 );
1281+ if (String (magic) == String (" !<arch>\n " )) {
1282+ while (!sim_f->eof_reached ()) {
1283+ // Read file metadata.
1284+ char name_short[17 ] = {};
1285+ char size_short[11 ] = {};
1286+ sim_f->get_buffer ((uint8_t *)&name_short[0 ], 16 );
1287+ sim_f->seek (sim_f->get_position () + 12 + 6 + 6 + 8 ); // Skip modification time, owner ID, group ID, file mode.
1288+ sim_f->get_buffer ((uint8_t *)&size_short[0 ], 10 );
1289+ sim_f->seek (sim_f->get_position () + 2 ); // Skip end marker.
1290+
1291+ int64_t file_size = String (size_short).to_int ();
1292+ int64_t next_off = sim_f->get_position () + file_size;
1293+
1294+ String name = String (name_short); // Skip extended name.
1295+ if (name.is_empty () || file_size == 0 ) {
1296+ break ;
1297+ }
1298+ if (name.begins_with (" #1/" )) {
1299+ int64_t name_len = String (name_short).replace (" #1/" , " " ).to_int ();
1300+ sim_f->seek (sim_f->get_position () + name_len);
1301+ }
1302+
1303+ // Read file content.
1304+ uint32_t obj_magic = sim_f->get_32 ();
1305+
1306+ bool swap = (obj_magic == 0xcffaedfe || obj_magic == 0xcefaedfe );
1307+ if (obj_magic == 0xcefaedfe || obj_magic == 0xfeedface || obj_magic == 0xcffaedfe || obj_magic == 0xfeedfacf ) {
1308+ uint32_t cputype = sim_f->get_32 ();
1309+ uint32_t cpusubtype = sim_f->get_32 ();
1310+ if (swap) {
1311+ cputype = BSWAP32 (cputype);
1312+ cpusubtype = BSWAP32 (cpusubtype);
1313+ }
1314+ if (r_cputype) {
1315+ *r_cputype = cputype;
1316+ }
1317+ if (r_cpusubtype) {
1318+ *r_cpusubtype = cpusubtype;
1319+ }
1320+ if (cputype == 0x100000c && cpusubtype == 0 ) {
1321+ has_arm64_image = true ;
1322+ }
1323+ break ;
1324+ }
1325+ sim_f->seek (next_off);
1326+ }
1327+ }
1328+ sim_f->close ();
1329+ }
1330+ }
1331+ }
1332+ return has_arm64_image;
1333+ }
1334+
1335+ int EditorExportPlatformIOS::_archive_convert_to_simulator (const String &p_path) const {
1336+ int commands_patched = 0 ;
1337+ Ref<FileAccess> sim_f = FileAccess::open (p_path, FileAccess::READ_WRITE);
1338+ if (sim_f.is_valid ()) {
1339+ char magic[9 ] = {};
1340+ sim_f->get_buffer ((uint8_t *)&magic[0 ], 8 );
1341+ if (String (magic) == String (" !<arch>\n " )) {
1342+ while (!sim_f->eof_reached ()) {
1343+ // Read file metadata.
1344+ char name_short[17 ] = {};
1345+ char size_short[11 ] = {};
1346+ sim_f->get_buffer ((uint8_t *)&name_short[0 ], 16 );
1347+ sim_f->seek (sim_f->get_position () + 12 + 6 + 6 + 8 ); // Skip modification time, owner ID, group ID, file mode.
1348+ sim_f->get_buffer ((uint8_t *)&size_short[0 ], 10 );
1349+ sim_f->seek (sim_f->get_position () + 2 ); // Skip end marker.
1350+
1351+ int64_t file_size = String (size_short).to_int ();
1352+ int64_t next_off = sim_f->get_position () + file_size;
1353+
1354+ String name = String (name_short); // Skip extended name.
1355+ if (name.is_empty () || file_size == 0 ) {
1356+ break ;
1357+ }
1358+ if (name.begins_with (" #1/" )) {
1359+ int64_t name_len = String (name_short).replace (" #1/" , " " ).to_int ();
1360+ sim_f->seek (sim_f->get_position () + name_len);
1361+ }
1362+
1363+ // Read file content.
1364+ uint32_t obj_magic = sim_f->get_32 ();
1365+
1366+ bool swap = (obj_magic == 0xcffaedfe || obj_magic == 0xcefaedfe );
1367+ if (obj_magic == 0xcefaedfe || obj_magic == 0xfeedface || obj_magic == 0xcffaedfe || obj_magic == 0xfeedfacf ) {
1368+ uint32_t cputype = sim_f->get_32 ();
1369+ uint32_t cpusubtype = sim_f->get_32 ();
1370+ uint32_t filetype = sim_f->get_32 ();
1371+ uint32_t ncmds = sim_f->get_32 ();
1372+ sim_f->get_32 (); // Commands total size.
1373+ sim_f->get_32 (); // Commands flags.
1374+ if (obj_magic == 0xcffaedfe || obj_magic == 0xfeedfacf ) {
1375+ sim_f->get_32 (); // Reserved, 64-bit only.
1376+ }
1377+ if (swap) {
1378+ ncmds = BSWAP32 (ncmds);
1379+ cputype = BSWAP32 (cputype);
1380+ cpusubtype = BSWAP32 (cpusubtype);
1381+ filetype = BSWAP32 (filetype);
1382+ }
1383+ if (cputype == 0x100000C && cpusubtype == 0 && filetype == 1 ) {
1384+ // ARM64, object file.
1385+ for (uint32_t i = 0 ; i < ncmds; i++) {
1386+ int64_t cmdofs = sim_f->get_position ();
1387+ uint32_t cmdid = sim_f->get_32 ();
1388+ uint32_t cmdsize = sim_f->get_32 ();
1389+ if (swap) {
1390+ cmdid = BSWAP32 (cmdid);
1391+ cmdsize = BSWAP32 (cmdsize);
1392+ }
1393+ if (cmdid == MachO::LoadCommandID::LC_BUILD_VERSION) {
1394+ int64_t platform = sim_f->get_32 ();
1395+ if (swap) {
1396+ platform = BSWAP32 (platform);
1397+ }
1398+ if (platform == MachO::PlatformID::PLATFORM_IOS) {
1399+ sim_f->seek (cmdofs + 4 + 4 );
1400+ uint32_t new_id = MachO::PlatformID::PLATFORM_IOSSIMULATOR;
1401+ if (swap) {
1402+ new_id = BSWAP32 (new_id);
1403+ }
1404+ sim_f->store_32 (new_id);
1405+ commands_patched++;
1406+ }
1407+ }
1408+ sim_f->seek (cmdofs + cmdsize);
1409+ }
1410+ }
1411+ }
1412+ sim_f->seek (next_off);
1413+ }
1414+ }
1415+ sim_f->close ();
1416+ }
1417+ return commands_patched;
1418+ }
1419+
12591420void EditorExportPlatformIOS::_check_xcframework_content (const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const {
12601421 Ref<PList> plist;
12611422 plist.instantiate ();
@@ -2260,6 +2421,82 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
22602421 return ERR_FILE_NOT_FOUND;
22612422 }
22622423
2424+ // HACK: We don't want to run the simulator library generation code anymore after GH-102179, but removing it
2425+ // triggers an internal compiler error with latest mingw-gcc... For now we bring it back as a workaround
2426+ // with a condition that should never be true (that project setting doesn't exist).
2427+
2428+ // Check and generate missing ARM64 simulator library.
2429+ if (ProjectSettings::get_singleton ()->has_setting (" __dummy_setting_blame_akien_if_you_define_this_somehow" )) {
2430+ String sim_lib_path = dest_dir + String (binary_name + " .xcframework" ).path_join (" ios-arm64_x86_64-simulator" ).path_join (" libgodot.a" );
2431+ String dev_lib_path = dest_dir + String (binary_name + " .xcframework" ).path_join (" ios-arm64" ).path_join (" libgodot.a" );
2432+ String tmp_lib_path = EditorPaths::get_singleton ()->get_temp_dir ().path_join (binary_name + " _lipo_" );
2433+ uint32_t cputype = 0 ;
2434+ uint32_t cpusubtype = 0 ;
2435+ if (!_archive_has_arm64 (sim_lib_path, &cputype, &cpusubtype) && _archive_has_arm64 (dev_lib_path) && FileAccess::exists (dev_lib_path)) {
2436+ add_message (EXPORT_MESSAGE_INFO, TTR (" Export" ), TTR (" ARM64 simulator library, generating from device library." ));
2437+
2438+ Vector<String> tmp_lib_files;
2439+ Vector<Vector2i> tmp_lib_cputypes;
2440+ // Extract/copy simulator lib.
2441+ if (FileAccess::exists (sim_lib_path)) {
2442+ if (LipO::is_lipo (sim_lib_path)) {
2443+ Ref<LipO> lipo;
2444+ lipo.instantiate ();
2445+ if (lipo->open_file (sim_lib_path)) {
2446+ for (int i = 0 ; i < lipo->get_arch_count (); i++) {
2447+ const String &f_name = tmp_lib_path + itos (tmp_lib_files.size ());
2448+ lipo->extract_arch (i, f_name);
2449+ tmp_lib_files.push_back (f_name);
2450+ tmp_lib_cputypes.push_back (Vector2i (lipo->get_arch_cputype (i), lipo->get_arch_cpusubtype (i)));
2451+ }
2452+ }
2453+ } else {
2454+ const String &f_name = tmp_lib_path + itos (tmp_lib_files.size ());
2455+ tmp_app_path->copy (sim_lib_path, f_name);
2456+ tmp_lib_files.push_back (f_name);
2457+ tmp_lib_cputypes.push_back (Vector2i (cputype, cpusubtype));
2458+ }
2459+ }
2460+ // Copy device lib.
2461+ if (LipO::is_lipo (dev_lib_path)) {
2462+ Ref<LipO> lipo;
2463+ lipo.instantiate ();
2464+ if (lipo->open_file (dev_lib_path)) {
2465+ for (int i = 0 ; i < lipo->get_arch_count (); i++) {
2466+ if (lipo->get_arch_cputype (i) == 0x100000c && lipo->get_arch_cpusubtype (i) == 0 ) {
2467+ const String &f_name = tmp_lib_path + itos (tmp_lib_files.size ());
2468+ lipo->extract_arch (i, f_name);
2469+ tmp_lib_files.push_back (f_name);
2470+ tmp_lib_cputypes.push_back (Vector2i (0x100000c , 0 )); // ARM64.
2471+ break ;
2472+ }
2473+ }
2474+ }
2475+ } else {
2476+ const String &f_name = tmp_lib_path + itos (tmp_lib_files.size ());
2477+ tmp_app_path->copy (dev_lib_path, f_name);
2478+ tmp_lib_files.push_back (f_name);
2479+ tmp_lib_cputypes.push_back (Vector2i (0x100000c , 0 )); // ARM64.
2480+ }
2481+
2482+ // Patch device lib.
2483+ int patch_count = _archive_convert_to_simulator (tmp_lib_path + itos (tmp_lib_files.size () - 1 ));
2484+ if (patch_count == 0 ) {
2485+ add_message (EXPORT_MESSAGE_WARNING, TTR (" Export" ), TTR (" Unable to generate ARM64 simulator library." ));
2486+ } else {
2487+ // Repack.
2488+ Ref<LipO> lipo;
2489+ lipo.instantiate ();
2490+ lipo->create_file (sim_lib_path, tmp_lib_files, tmp_lib_cputypes);
2491+ }
2492+
2493+ // Cleanup.
2494+ for (const String &E : tmp_lib_files) {
2495+ tmp_app_path->remove (E);
2496+ }
2497+ }
2498+ }
2499+
22632500 // Generate translations files.
22642501
22652502 Dictionary appnames = GLOBAL_GET (" application/config/name_localized" );
0 commit comments