@@ -1256,6 +1256,167 @@ struct ExportLibsData {
1256
1256
String dest_dir;
1257
1257
};
1258
1258
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
+
1259
1420
void EditorExportPlatformIOS::_check_xcframework_content (const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const {
1260
1421
Ref<PList> plist;
1261
1422
plist.instantiate ();
@@ -2260,6 +2421,82 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
2260
2421
return ERR_FILE_NOT_FOUND;
2261
2422
}
2262
2423
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 (" ios_generate_simulator_library_if_missing" )) {
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
+
2263
2500
// Generate translations files.
2264
2501
2265
2502
Dictionary appnames = GLOBAL_GET (" application/config/name_localized" );
0 commit comments