From 683f96df35d9966e95ed525860102047a5f0defd Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Tue, 26 Jan 2021 16:55:34 +0200 Subject: [PATCH 1/6] Add separate `simulator` flag for iOS build, change main library to `xcframework`. Build and export iOS Mono libs as `.xcframework`s, for Apple Silicon iOS simulator support. --- .../godot_ios.xcodeproj/project.pbxproj | 8 ++-- .../ios_xcode/libgodot.iphone.debug.fat.a | 0 .../Info.plist | 40 +++++++++++++++++++ .../ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + .../ios_xcode/libgodot.iphone.release.fat.a | 0 .../Info.plist | 40 +++++++++++++++++++ .../ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + .../libmono-native.xcframework/Info.plist | 40 +++++++++++++++++++ .../ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + .../Info.plist | 40 +++++++++++++++++++ .../ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + .../libmonosgen-2.0.xcframework/Info.plist | 40 +++++++++++++++++++ .../ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + modules/mono/build_scripts/mono_configure.py | 19 +++++++-- .../GodotTools/Export/AotBuilder.cs | 11 +++-- platform/iphone/detect.py | 23 +++++++---- platform/iphone/export/export.cpp | 12 +++--- 22 files changed, 260 insertions(+), 23 deletions(-) delete mode 100644 misc/dist/ios_xcode/libgodot.iphone.debug.fat.a create mode 100644 misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/Info.plist create mode 100644 misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64/empty create mode 100644 misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64_x86_64-simulator/empty delete mode 100644 misc/dist/ios_xcode/libgodot.iphone.release.fat.a create mode 100644 misc/dist/ios_xcode/libgodot.iphone.release.xcframework/Info.plist create mode 100644 misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64/empty create mode 100644 misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64_x86_64-simulator/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-native.xcframework/Info.plist create mode 100644 misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64_x86_64-simulator/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/Info.plist create mode 100644 misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64_x86_64-simulator/empty create mode 100644 misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/Info.plist create mode 100644 misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64/empty create mode 100644 misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64_x86_64-simulator/empty diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index fd609a73e8c..6ca5e888b5a 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 1F1575721F582BE20003B888 /* dylibs in Resources */ = {isa = PBXBuildFile; fileRef = 1F1575711F582BE20003B888 /* dylibs */; }; - DEADBEEF2F582BE20003B888 /* $binary.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DEADBEEF1F582BE20003B888 /* $binary.a */; }; + DEADBEEF2F582BE20003B888 /* $binary.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEADBEEF1F582BE20003B888 /* $binary.xcframework */; }; $modules_buildfile 1FF8DBB11FBA9DE1009DE660 /* dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */; }; D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07CD44D1C5D589C00B7FB28 /* Images.xcassets */; }; @@ -33,7 +33,7 @@ /* Begin PBXFileReference section */ 1F1575711F582BE20003B888 /* dylibs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dylibs; path = "$binary/dylibs"; sourceTree = ""; }; - DEADBEEF1F582BE20003B888 /* $binary.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = godot; path = "$binary.a"; sourceTree = ""; }; + DEADBEEF1F582BE20003B888 /* $binary.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = godot; path = "$binary.xcframework"; sourceTree = ""; }; $modules_fileref 1FF4C1881F584E6300A41E41 /* $binary.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "$binary.entitlements"; sourceTree = ""; }; 1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dummy.cpp; sourceTree = ""; }; @@ -52,7 +52,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DEADBEEF2F582BE20003B888 /* $binary.a */, + DEADBEEF2F582BE20003B888 /* $binary.xcframework */, $modules_buildphase $additional_pbx_frameworks_build ); @@ -84,7 +84,7 @@ D0BCFE3618AEBDA2004A7AAE /* Frameworks */ = { isa = PBXGroup; children = ( - DEADBEEF1F582BE20003B888 /* $binary.a */, + DEADBEEF1F582BE20003B888 /* $binary.xcframework */, $modules_buildgrp $additional_pbx_frameworks_refs ); diff --git a/misc/dist/ios_xcode/libgodot.iphone.debug.fat.a b/misc/dist/ios_xcode/libgodot.iphone.debug.fat.a deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/Info.plist b/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/Info.plist new file mode 100644 index 00000000000..846533594fd --- /dev/null +++ b/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libgodot.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libgodot.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64/empty b/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/ios_xcode/libgodot.iphone.debug.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/ios_xcode/libgodot.iphone.release.fat.a b/misc/dist/ios_xcode/libgodot.iphone.release.fat.a deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/Info.plist b/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/Info.plist new file mode 100644 index 00000000000..846533594fd --- /dev/null +++ b/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libgodot.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libgodot.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64/empty b/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/ios_xcode/libgodot.iphone.release.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-native.xcframework/Info.plist b/misc/dist/iphone-mono-libs/libmono-native.xcframework/Info.plist new file mode 100644 index 00000000000..afb8cdc88a8 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-native.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libmono-native.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libmono-native.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64/empty b/misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-native.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/Info.plist b/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/Info.plist new file mode 100644 index 00000000000..be39af11428 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libmono-profiler-log.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libmono-profiler-log.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64/empty b/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-profiler-log.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/Info.plist b/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/Info.plist new file mode 100644 index 00000000000..6eb5feb91cf --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libmonosgen.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libmonosgen.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64/empty b/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmonosgen-2.0.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 68696278736..2d9d59ff9f8 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -86,7 +86,7 @@ def configure(env, env_mono): is_android = env["platform"] == "android" is_javascript = env["platform"] == "javascript" is_ios = env["platform"] == "iphone" - is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"] + is_ios_sim = is_ios and env["ios_simulator"] tools_enabled = env["tools"] mono_static = env["mono_static"] @@ -271,9 +271,20 @@ def configure(env, env_mono): arch = env["arch"] def copy_mono_lib(libname_wo_ext): - copy_file( - mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.iphone.%s.a" % (libname_wo_ext, arch) - ) + if is_ios_sim: + copy_file( + mono_lib_path, + "#bin", + libname_wo_ext + ".a", + "%s.iphone.%s.simulator.a" % (libname_wo_ext, arch), + ) + else: + copy_file( + mono_lib_path, + "#bin", + libname_wo_ext + ".a", + "%s.iphone.%s.a" % (libname_wo_ext, arch), + ) # Copy Mono libraries to the output folder. These are meant to be bundled with # the export templates and added to the Xcode project when exporting a game. diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index f9eb405ce6c..372cccc46ec 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -340,9 +340,14 @@ MONO_AOT_MODE_LAST = 1000, string MonoLibFromTemplate(string libFileName) => Path.Combine(Internal.FullTemplatesDir, "iphone-mono-libs", MonoLibFile(libFileName)); - exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmonosgen-2.0")); + string MonoFrameworkFile(string frameworkFileName) => frameworkFileName + ".xcframework"; - exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-native")); + string MonoFrameworkFromTemplate(string frameworkFileName) => + Path.Combine(Internal.FullTemplatesDir, "iphone-mono-libs", MonoFrameworkFile(frameworkFileName)); + + exporter.AddIosProjectStaticLib(MonoFrameworkFromTemplate("libmonosgen-2.0")); + + exporter.AddIosProjectStaticLib(MonoFrameworkFromTemplate("libmono-native")); if (aotOpts.UseInterpreter) { @@ -366,7 +371,7 @@ MONO_AOT_MODE_LAST = 1000, // functions in System.Native/libmono-native). Instead, we should use cecil to search for // DllImports in assemblies and pass them to 'ld' as '-u/--undefined {pinvoke_symbol}'. exporter.AddIosLinkerFlags("-rdynamic"); - exporter.AddIosLinkerFlags($"-force_load \"$(SRCROOT)/{MonoLibFile("libmono-native")}\""); + exporter.AddIosLinkerFlags($"-force_load \"$(SRCROOT)/{MonoFrameworkFile("libmono-native")}\""); } /// Converts an assembly name to a valid symbol name in the same way the AOT compiler does diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index de3493f1895..288dafb6c3e 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -33,6 +33,7 @@ def get_opts(): "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain", ), ("IPHONESDK", "Path to the iPhone SDK", ""), + BoolVariable("ios_simulator", "Build for iOS Simulator", False), BoolVariable("ios_exceptions", "Enable exceptions", False), ("ios_triple", "Triple for ios toolchain", ""), ] @@ -106,26 +107,35 @@ def configure(env): ## Compile flags - if env["arch"] == "x86" or env["arch"] == "x86_64": + if env["ios_simulator"]: detect_darwin_sdk_path("iphonesimulator", env) + env.Append(CCFLAGS=["-mios-simulator-version-min=10.0"]) + env.Append(LINKFLAGS=["-mios-simulator-version-min=10.0"]) + env.extra_suffix = ".simulator" + env.extra_suffix + else: + detect_darwin_sdk_path("iphone", env) + env.Append(CCFLAGS=["-miphoneos-version-min=10.0"]) + env.Append(LINKFLAGS=["-miphoneos-version-min=10.0"]) + + if env["arch"] == "x86" or env["arch"] == "x86_64": env["ENV"]["MACOSX_DEPLOYMENT_TARGET"] = "10.9" arch_flag = "i386" if env["arch"] == "x86" else env["arch"] env.Append( CCFLAGS=( "-arch " + arch_flag - + " -fobjc-arc -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK -mios-simulator-version-min=10.0" + + " -fobjc-arc -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fblocks -fasm-blocks -isysroot $IPHONESDK" ).split() ) elif env["arch"] == "arm": detect_darwin_sdk_path("iphone", env) env.Append( - CCFLAGS='-fobjc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=10.0 -MMD -MT dependencies'.split() + CCFLAGS='-fobjc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -isysroot $IPHONESDK -fvisibility=hidden -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -MMD -MT dependencies'.split() ) elif env["arch"] == "arm64": detect_darwin_sdk_path("iphone", env) env.Append( - CCFLAGS="-fobjc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -miphoneos-version-min=10.0 -isysroot $IPHONESDK".split() + CCFLAGS="-fobjc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies -isysroot $IPHONESDK".split() ) env.Append(CPPDEFINES=["NEED_LONG_INT"]) env.Append(CPPDEFINES=["LIBYUV_DISABLE_NEON"]) @@ -148,7 +158,6 @@ def configure(env): LINKFLAGS=[ "-arch", arch_flag, - "-mios-simulator-version-min=10.0", "-isysroot", "$IPHONESDK", "-Xlinker", @@ -159,9 +168,9 @@ def configure(env): ] ) elif env["arch"] == "arm": - env.Append(LINKFLAGS=["-arch", "armv7", "-Wl,-dead_strip", "-miphoneos-version-min=10.0"]) + env.Append(LINKFLAGS=["-arch", "armv7", "-Wl,-dead_strip"]) if env["arch"] == "arm64": - env.Append(LINKFLAGS=["-arch", "arm64", "-Wl,-dead_strip", "-miphoneos-version-min=10.0"]) + env.Append(LINKFLAGS=["-arch", "arm64", "-Wl,-dead_strip"]) env.Append( LINKFLAGS=[ diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 7cdfd6f16de..0674ee68b0f 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -1504,9 +1504,9 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p return ERR_SKIP; } - String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".fat.a"; + String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".xcframework"; - print_line("Static library: " + library_to_use); + print_line("Static framework: " + library_to_use); String pkg_name; if (p_preset->get("application/name") != "") { pkg_name = p_preset->get("application/name"); // app_name @@ -1592,7 +1592,7 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p if (files_to_parse.has(file)) { _fix_config_file(p_preset, data, config_data, p_debug); } else if (file.begins_with("libgodot.iphone")) { - if (file != library_to_use) { + if (!file.begins_with(library_to_use) || file.ends_with(String("/empty"))) { ret = unzGoToNextFile(src_pkg_zip); continue; //ignore! } @@ -1600,7 +1600,7 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p #if defined(OSX_ENABLED) || defined(X11_ENABLED) is_execute = true; #endif - file = "godot_ios.a"; + file = file.replace(library_to_use, binary_name + ".xcframework"); } if (file == project_file) { @@ -1670,7 +1670,9 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p for (int j = 0; j < project_static_libs.size(); j++) { const String &static_lib_path = project_static_libs[j]; String dest_lib_file_path = dest_dir + static_lib_path.get_file(); - Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path); + + bool dir_exists = tmp_app_path->dir_exists(static_lib_path); + Error lib_copy_err = dir_exists ? tmp_app_path->copy_dir(static_lib_path, dest_lib_file_path) : tmp_app_path->copy(static_lib_path, dest_lib_file_path); if (lib_copy_err != OK) { ERR_PRINTS("Can't copy '" + static_lib_path + "'."); memdelete(tmp_app_path); From 7569f2dccb83aa63d4145692974c677e3192b492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etchevery?= Date: Fri, 21 May 2021 05:52:57 +0200 Subject: [PATCH 2/6] Fix copying Mono shared libs on macOS --- modules/mono/build_scripts/mono_configure.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 2d9d59ff9f8..aeb25714010 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -551,12 +551,16 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir): if not os.path.isdir(target_mono_lib_dir): os.makedirs(target_mono_lib_dir) + src_mono_lib_dir = os.path.join(mono_root, "lib") + lib_file_names = [] if platform == "osx": - lib_file_names = [ - lib_name + ".dylib" - for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"] - ] + lib_file_names = [lib_name + ".dylib" for lib_name in ["libmono-btls-shared", "libMonoPosixHelper"]] + + if os.path.isfile(os.path.join(src_mono_lib_dir, "libmono-native-compat.dylib")): + lib_file_names += ["libmono-native-compat.dylib"] + else: + lib_file_names += ["libmono-native.dylib"] elif is_unix_like(platform): lib_file_names = [ lib_name + ".so" @@ -573,7 +577,7 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir): ] for lib_file_name in lib_file_names: - copy_if_exists(os.path.join(mono_root, "lib", lib_file_name), target_mono_lib_dir) + copy_if_exists(os.path.join(src_mono_lib_dir, lib_file_name), target_mono_lib_dir) def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext): From c9047de455ed3edb1dc576293fa19fcda9654dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etchevery?= Date: Fri, 21 May 2021 06:20:55 +0200 Subject: [PATCH 3/6] C#+iOS: Fix simulator builds Replaced obsolete preprocessor check for simulator/device in C code. Architecture can no longer be used to determine this with Apple Silicon. The new code uses `TARGET_OS_SIMULATOR` from `TargetConditionals.h`. We have some mono libs which can only be used in devide builds. We were adding them as static libs. Previously it was only causing warnings because missing arch for the simulator, but now this is treated as an error. To fix this we turn them into xcframeworks with dummy static libs for the simulator and the actual ones for devices. --- .../libmono-ee-interp.xcframework/Info.plist | 40 +++ .../ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + .../Info.plist | 40 +++ .../ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + .../libmono-ilgen.xcframework/Info.plist | 40 +++ .../libmono-ilgen.xcframework/ios-arm64/empty | 1 + .../ios-arm64_x86_64-simulator/empty | 1 + .../GodotTools/Export/AotBuilder.cs | 288 ++++++++++++------ 10 files changed, 314 insertions(+), 100 deletions(-) create mode 100644 misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/Info.plist create mode 100644 misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64_x86_64-simulator/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/Info.plist create mode 100644 misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64_x86_64-simulator/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/Info.plist create mode 100644 misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64/empty create mode 100644 misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64_x86_64-simulator/empty diff --git a/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/Info.plist b/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/Info.plist new file mode 100644 index 00000000000..85b0b982098 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libmono-ee-interp.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libmono-ee-interp.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64/empty b/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-ee-interp.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/Info.plist b/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/Info.plist new file mode 100644 index 00000000000..feadce5e97d --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libmono-icall-table.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libmono-icall-table.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64/empty b/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-icall-table.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/Info.plist b/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/Info.plist new file mode 100644 index 00000000000..95abbe7a94f --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/Info.plist @@ -0,0 +1,40 @@ + + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + libmono-ilgen.a + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + libmono-ilgen.a + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64/empty b/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64_x86_64-simulator/empty b/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64_x86_64-simulator/empty new file mode 100644 index 00000000000..bd3e8943336 --- /dev/null +++ b/misc/dist/iphone-mono-libs/libmono-ilgen.xcframework/ios-arm64_x86_64-simulator/empty @@ -0,0 +1 @@ +Dummy file to make dylibs folder exported diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index 372cccc46ec..92aeb25e7ac 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -22,7 +22,12 @@ namespace GodotTools.Export public bool FullAot; private bool _useInterpreter; - public bool UseInterpreter { get => _useInterpreter && !LLVMOnly; set => _useInterpreter = value; } + + public bool UseInterpreter + { + get => _useInterpreter && !LLVMOnly; + set => _useInterpreter = value; + } public string[] ExtraAotOptions; public string[] ExtraOptimizerOptions; @@ -82,7 +87,6 @@ namespace GodotTools.Export public static void CompileAssembliesForAndroid(ExportPlugin exporter, bool isDebug, string[] abis, AotOptions aotOpts, string aotTempDir, IDictionary assemblies, string bclDir) { - foreach (var assembly in assemblies) { string assemblyName = assembly.Key; @@ -107,7 +111,7 @@ namespace GodotTools.Export ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir); // The Godot exporter expects us to pass the abi in the tags parameter - exporter.AddSharedObject(soFilePath, tags: new[] { abi }); + exporter.AddSharedObject(soFilePath, tags: new[] {abi}); } } } @@ -146,11 +150,101 @@ namespace GodotTools.Export public static void CompileAssembliesForiOS(ExportPlugin exporter, bool isDebug, string[] architectures, AotOptions aotOpts, string aotTempDir, IDictionary assemblies, string bclDir) { + void RunAr(IEnumerable objFilePaths, string outputFilePath) + { + var arArgs = new List() + { + "cr", + outputFilePath + }; + + foreach (string objFilePath in objFilePaths) + arArgs.Add(objFilePath); + + int arExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("ar"), arArgs); + if (arExitCode != 0) + throw new Exception($"Command 'ar' exited with code: {arExitCode}"); + } + + void RunLipo(IEnumerable libFilePaths, string outputFilePath) + { + var lipoArgs = new List(); + lipoArgs.Add("-create"); + lipoArgs.AddRange(libFilePaths); + lipoArgs.Add("-output"); + lipoArgs.Add(outputFilePath); + + int lipoExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("lipo"), lipoArgs); + if (lipoExitCode != 0) + throw new Exception($"Command 'lipo' exited with code: {lipoExitCode}"); + } + + void CreateDummyLibForSimulator(string name, string xcFrameworkPath = null) + { + xcFrameworkPath = xcFrameworkPath ?? MonoFrameworkFromTemplate(name); + string simulatorSubDir = Path.Combine(xcFrameworkPath, "ios-arm64_x86_64-simulator"); + + string libFilePath = Path.Combine(simulatorSubDir, name + ".a"); + + if (File.Exists(libFilePath)) + return; + + string CompileForArch(string arch) + { + string baseFilePath = Path.Combine(aotTempDir, $"{name}.{arch}"); + string sourceFilePath = baseFilePath + ".c"; + + string source = $"int _{AssemblyNameToAotSymbol(name)}() {{ return 0; }}\n"; + File.WriteAllText(sourceFilePath, source); + + const string iOSPlatformName = "iPhoneSimulator"; + const string versionMin = "10.0"; + string iOSSdkPath = Path.Combine(XcodeHelper.XcodePath, + $"Contents/Developer/Platforms/{iOSPlatformName}.platform/Developer/SDKs/{iOSPlatformName}.sdk"); + + string objFilePath = baseFilePath + ".o"; + + var clangArgs = new[] + { + "-isysroot", iOSSdkPath, + $"-miphonesimulator-version-min={versionMin}", + "-arch", arch, + "-c", + "-o", objFilePath, + sourceFilePath + }; + + int clangExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("clang"), clangArgs); + if (clangExitCode != 0) + throw new Exception($"Command 'clang' exited with code: {clangExitCode}"); + + string arOutputFilePath = Path.Combine(aotTempDir, baseFilePath + ".a"); + RunAr(new[] {objFilePath}, arOutputFilePath); + + return arOutputFilePath; + } + + RunLipo(new[] {CompileForArch("arm64"), CompileForArch("x86_64")}, libFilePath); + } + + string projectAssemblyName = GodotSharpEditor.ProjectAssemblyName; + string libAotName = $"lib-aot-{projectAssemblyName}"; + + string libAotXcFrameworkPath = Path.Combine(aotTempDir, $"{libAotName}.xcframework"); + string libAotXcFrameworkDevicePath = Path.Combine(libAotXcFrameworkPath, "ios-arm64"); + string libAotXcFrameworkSimPath = Path.Combine(libAotXcFrameworkPath, "ios-arm64_x86_64-simulator"); + + Directory.CreateDirectory(libAotXcFrameworkPath); + Directory.CreateDirectory(libAotXcFrameworkDevicePath); + Directory.CreateDirectory(libAotXcFrameworkSimPath); + + string libAotFileName = $"{libAotName}.a"; + string libAotFilePath = Path.Combine(libAotXcFrameworkDevicePath, libAotFileName); + var cppCode = new StringBuilder(); var aotModuleInfoSymbols = new List(assemblies.Count); - // {arch: paths} - var objFilePathsForiOSArch = architectures.ToDictionary(arch => arch, arch => new List(assemblies.Count)); + var aotObjFilePaths = new List(assemblies.Count); foreach (var assembly in assemblies) { @@ -160,36 +254,29 @@ namespace GodotTools.Export string asmFileName = assemblyName + ".dll.S"; string objFileName = assemblyName + ".dll.o"; - foreach (string arch in architectures) { - string aotArchTempDir = Path.Combine(aotTempDir, arch); - string asmFilePath = Path.Combine(aotArchTempDir, asmFileName); + string asmFilePath = Path.Combine(aotTempDir, asmFileName); - var compilerArgs = GetAotCompilerArgs(OS.Platforms.iOS, isDebug, arch, aotOpts, assemblyPath, asmFilePath); + var compilerArgs = GetAotCompilerArgs(OS.Platforms.iOS, isDebug, "arm64", aotOpts, assemblyPath, asmFilePath); - // Make sure the output directory exists - Directory.CreateDirectory(aotArchTempDir); - - string compilerDirPath = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "aot-compilers", $"{OS.Platforms.iOS}-{arch}"); + string compilerDirPath = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "aot-compilers", $"{OS.Platforms.iOS}-arm64"); ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir); // Assembling - bool isSim = arch == "i386" || arch == "x86_64"; // Shouldn't really happen as we don't do AOT for the simulator - string versionMinName = isSim ? "iphonesimulator" : "iphoneos"; - string iOSPlatformName = isSim ? "iPhoneSimulator" : "iPhoneOS"; + const string iOSPlatformName = "iPhoneOS"; const string versionMin = "10.0"; // TODO: Turn this hard-coded version into an exporter setting string iOSSdkPath = Path.Combine(XcodeHelper.XcodePath, - $"Contents/Developer/Platforms/{iOSPlatformName}.platform/Developer/SDKs/{iOSPlatformName}.sdk"); + $"Contents/Developer/Platforms/{iOSPlatformName}.platform/Developer/SDKs/{iOSPlatformName}.sdk"); - string objFilePath = Path.Combine(aotArchTempDir, objFileName); + string objFilePath = Path.Combine(aotTempDir, objFileName); var clangArgs = new List() { "-isysroot", iOSSdkPath, "-Qunused-arguments", - $"-m{versionMinName}-version-min={versionMin}", - "-arch", arch, + $"-miphoneos-version-min={versionMin}", + "-arch", "arm64", "-c", "-o", objFilePath, "-x", "assembler" @@ -204,18 +291,67 @@ namespace GodotTools.Export if (clangExitCode != 0) throw new Exception($"Command 'clang' exited with code: {clangExitCode}"); - objFilePathsForiOSArch[arch].Add(objFilePath); + aotObjFilePaths.Add(objFilePath); } aotModuleInfoSymbols.Add($"mono_aot_module_{AssemblyNameToAotSymbol(assemblyName)}_info"); } - // Generate driver code - cppCode.AppendLine("#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)"); - cppCode.AppendLine("#define IOS_DEVICE"); - cppCode.AppendLine("#endif"); + RunAr(aotObjFilePaths, libAotFilePath); - cppCode.AppendLine("#ifdef IOS_DEVICE"); + // Archive the AOT object files into a static library + + File.WriteAllText(Path.Combine(libAotXcFrameworkPath, "Info.plist"), + $@" + + + + AvailableLibraries + + + LibraryIdentifier + ios-arm64 + LibraryPath + {libAotFileName} + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + {libAotFileName} + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + +"); + + // Add the fat AOT static library to the Xcode project + CreateDummyLibForSimulator(libAotName, libAotXcFrameworkPath); + exporter.AddIosProjectStaticLib(libAotXcFrameworkPath); + + // Generate driver code + cppCode.AppendLine("#include "); + + cppCode.AppendLine("#if !TARGET_OS_SIMULATOR"); cppCode.AppendLine("extern \"C\" {"); cppCode.AppendLine("// Mono API"); cppCode.AppendLine(@" @@ -280,59 +416,11 @@ MONO_AOT_MODE_LAST = 1000, cppCode.AppendLine("} // gd_mono_setup_aot"); cppCode.AppendLine("} // extern \"C\""); - cppCode.AppendLine("#endif // IOS_DEVICE"); + cppCode.AppendLine("#endif // !TARGET_OS_SIMULATOR"); // Add the driver code to the Xcode project exporter.AddIosCppCode(cppCode.ToString()); - // Archive the AOT object files into a static library - - var arFilePathsForAllArchs = new List(); - string projectAssemblyName = GodotSharpEditor.ProjectAssemblyName; - - foreach (var archPathsPair in objFilePathsForiOSArch) - { - string arch = archPathsPair.Key; - var objFilePaths = archPathsPair.Value; - - string arOutputFilePath = Path.Combine(aotTempDir, $"lib-aot-{projectAssemblyName}.{arch}.a"); - - var arArgs = new List() - { - "cr", - arOutputFilePath - }; - - foreach (string objFilePath in objFilePaths) - arArgs.Add(objFilePath); - - int arExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("ar"), arArgs); - if (arExitCode != 0) - throw new Exception($"Command 'ar' exited with code: {arExitCode}"); - - arFilePathsForAllArchs.Add(arOutputFilePath); - } - - // It's lipo time - - string fatOutputFileName = $"lib-aot-{projectAssemblyName}.fat.a"; - string fatOutputFilePath = Path.Combine(aotTempDir, fatOutputFileName); - - var lipoArgs = new List(); - lipoArgs.Add("-create"); - lipoArgs.AddRange(arFilePathsForAllArchs); - lipoArgs.Add("-output"); - lipoArgs.Add(fatOutputFilePath); - - int lipoExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("lipo"), lipoArgs); - if (lipoExitCode != 0) - throw new Exception($"Command 'lipo' exited with code: {lipoExitCode}"); - - // TODO: Add the AOT lib and interpreter libs as device only to suppress warnings when targeting the simulator - - // Add the fat AOT static library to the Xcode project - exporter.AddIosProjectStaticLib(fatOutputFilePath); - // Add the required Mono libraries to the Xcode project string MonoLibFile(string libFileName) => libFileName + ".iphone.fat.a"; @@ -351,9 +439,12 @@ MONO_AOT_MODE_LAST = 1000, if (aotOpts.UseInterpreter) { - exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-ee-interp")); - exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-icall-table")); - exporter.AddIosProjectStaticLib(MonoLibFromTemplate("libmono-ilgen")); + CreateDummyLibForSimulator("libmono-ee-interp"); + exporter.AddIosProjectStaticLib(MonoFrameworkFromTemplate("libmono-ee-interp")); + CreateDummyLibForSimulator("libmono-icall-table"); + exporter.AddIosProjectStaticLib(MonoFrameworkFromTemplate("libmono-icall-table")); + CreateDummyLibForSimulator("libmono-ilgen"); + exporter.AddIosProjectStaticLib(MonoFrameworkFromTemplate("libmono-ilgen")); } // TODO: Turn into an exporter option @@ -379,11 +470,8 @@ MONO_AOT_MODE_LAST = 1000, { var builder = new StringBuilder(); - foreach (var charByte in Encoding.UTF8.GetBytes(assemblyName)) - { - char @char = (char)charByte; - builder.Append(Char.IsLetterOrDigit(@char) || @char == '_' ? @char : '_'); - } + foreach (char @char in assemblyName) + builder.Append(char.IsLetterOrDigit(@char) || @char == '_' ? @char : '_'); return builder.ToString(); } @@ -582,27 +670,27 @@ MONO_AOT_MODE_LAST = 1000, { case OS.Platforms.Windows: case OS.Platforms.UWP: - { - string arch = bits == "64" ? "x86_64" : "i686"; - return $"windows-{arch}"; - } + { + string arch = bits == "64" ? "x86_64" : "i686"; + return $"windows-{arch}"; + } case OS.Platforms.OSX: - { - Debug.Assert(bits == null || bits == "64"); - string arch = "x86_64"; - return $"{platform}-{arch}"; - } + { + Debug.Assert(bits == null || bits == "64"); + string arch = "x86_64"; + return $"{platform}-{arch}"; + } case OS.Platforms.X11: case OS.Platforms.Server: - { - string arch = bits == "64" ? "x86_64" : "i686"; - return $"linux-{arch}"; - } + { + string arch = bits == "64" ? "x86_64" : "i686"; + return $"linux-{arch}"; + } case OS.Platforms.Haiku: - { - string arch = bits == "64" ? "x86_64" : "i686"; - return $"{platform}-{arch}"; - } + { + string arch = bits == "64" ? "x86_64" : "i686"; + return $"{platform}-{arch}"; + } default: throw new NotSupportedException($"Platform not supported: {platform}"); } From 21a739e3b1941df287a8a1ec441a41fd74e6f623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etchevery?= Date: Fri, 21 May 2021 06:24:15 +0200 Subject: [PATCH 4/6] C#+iOS: Fix P/Invoke symbols being stripped by the linker We use `Mono.Cecil` to search for P/Invoke methods in assemblies in order to collect symbols that we must prevent from being stripped. We could pass the symbols as `-u` linker arguments (`-Wl,-u,symbol`) for the native target (not for the project), but it was simpler to generate referencing code and avoid changes to Godot's iOS exporter. --- .../GodotTools/Export/AotBuilder.cs | 115 +++++++++++++++++- .../GodotTools/GodotTools/GodotTools.csproj | 1 + 2 files changed, 110 insertions(+), 6 deletions(-) diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index 92aeb25e7ac..9cefbdcc1bc 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -4,7 +4,10 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using Godot; +using GodotTools.Core; using GodotTools.Internals; +using Mono.Cecil; using Directory = GodotTools.Utils.Directory; using File = GodotTools.Utils.File; using OS = GodotTools.Utils.OS; @@ -415,6 +418,30 @@ MONO_AOT_MODE_LAST = 1000, cppCode.AppendLine($"\tmono_jit_set_aot_mode({aotModeStr});"); cppCode.AppendLine("} // gd_mono_setup_aot"); + + // Prevent symbols from being stripped + + var symbols = CollectSymbols(assemblies); + + foreach (string symbol in symbols) + { + cppCode.Append("extern void *"); + cppCode.Append(symbol); + cppCode.AppendLine(";"); + } + + cppCode.AppendLine("__attribute__((used)) __attribute__((optnone)) static void __godot_symbol_referencer() {"); + cppCode.AppendLine("\tvoid *aux;"); + + foreach (string symbol in symbols) + { + cppCode.Append("\taux = "); + cppCode.Append(symbol); + cppCode.AppendLine(";"); + } + + cppCode.AppendLine("} // __godot_symbol_referencer"); + cppCode.AppendLine("} // extern \"C\""); cppCode.AppendLine("#endif // !TARGET_OS_SIMULATOR"); @@ -456,13 +483,89 @@ MONO_AOT_MODE_LAST = 1000, exporter.AddIosFramework("libiconv.tbd"); exporter.AddIosFramework("GSS.framework"); exporter.AddIosFramework("CFNetwork.framework"); + } - // Force load and export dynamic are needed for the linker to not strip required symbols. - // In theory we shouldn't be relying on this for P/Invoked functions (as is the case with - // functions in System.Native/libmono-native). Instead, we should use cecil to search for - // DllImports in assemblies and pass them to 'ld' as '-u/--undefined {pinvoke_symbol}'. - exporter.AddIosLinkerFlags("-rdynamic"); - exporter.AddIosLinkerFlags($"-force_load \"$(SRCROOT)/{MonoFrameworkFile("libmono-native")}\""); + private static List CollectSymbols(IDictionary assemblies) + { + var symbols = new List(); + + var resolver = new DefaultAssemblyResolver(); + foreach (var searchDir in resolver.GetSearchDirectories()) + resolver.RemoveSearchDirectory(searchDir); + foreach (var searchDir in assemblies + .Select(a => a.Value.GetBaseDir().NormalizePath()).Distinct()) + { + resolver.AddSearchDirectory(searchDir); + } + + AssemblyDefinition ReadAssembly(string fileName) + => AssemblyDefinition.ReadAssembly(fileName, + new ReaderParameters {AssemblyResolver = resolver}); + + foreach (var assembly in assemblies) + { + using (var assemblyDef = ReadAssembly(assembly.Value)) + CollectSymbolsFromAssembly(assemblyDef, symbols); + } + + return symbols; + } + + private static void CollectSymbolsFromAssembly(AssemblyDefinition assembly, ICollection symbols) + { + if (!assembly.MainModule.HasTypes) + return; + + foreach (var type in assembly.MainModule.Types) + { + CollectSymbolsFromType(type, symbols); + } + } + + private static void CollectSymbolsFromType(TypeDefinition type, ICollection symbols) + { + if (type.HasNestedTypes) + { + foreach (var nestedType in type.NestedTypes) + CollectSymbolsFromType(nestedType, symbols); + } + + if (type.Module.HasModuleReferences) + CollectPInvokeSymbols(type, symbols); + } + + private static void CollectPInvokeSymbols(TypeDefinition type, ICollection symbols) + { + if (!type.HasMethods) + return; + + foreach (var method in type.Methods) + { + if (!method.IsPInvokeImpl || !method.HasPInvokeInfo) + continue; + + var pInvokeInfo = method.PInvokeInfo; + + if (pInvokeInfo == null) + continue; + + switch (pInvokeInfo.Module.Name) + { + case "__Internal": + case "libSystem.Net.Security.Native": + case "System.Net.Security.Native": + case "libSystem.Security.Cryptography.Native.Apple": + case "System.Security.Cryptography.Native.Apple": + case "libSystem.Native": + case "System.Native": + case "libSystem.Globalization.Native": + case "System.Globalization.Native": + { + symbols.Add(pInvokeInfo.EntryPoint); + break; + } + } + } } /// Converts an assembly name to a valid symbol name in the same way the AOT compiler does diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index 2c4537f5254..7139275f0aa 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -20,6 +20,7 @@ + $(GodotApiAssembliesDir)/GodotSharp.dll False From 4838e609ee9d46a2dafeeb65cd5ca6bf05819756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etchevery?= Date: Fri, 21 May 2021 06:25:24 +0200 Subject: [PATCH 5/6] C#+iOS: Fixes for games exported with `Use Interpreter` disabled Added `SystemConfiguration.framework` to the Xcode project to fix undefined symbols errors building without the interpreter, like: `_SCNetworkReachabilityScheduleWithRunLoop`. Added explicit static constructors to the generated `NativeCalls` class to avoid a `TypeInitializationException` at startup when Godot attempts to read the static fields (like `godot_api_hash`) from this class. This seems to be an issue with Mono's AOT compiler and classes with the `beforefieldinit` attribute. Not sure if it only happens when the fields are only accessed via reflection as was our case. Explicitly declaring the static constructor makes the C# compiler not add the `beforefieldinit` attribute to the class. --- .../GodotTools/Export/AotBuilder.cs | 2 ++ modules/mono/editor/bindings_generator.cpp | 23 ++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index 9cefbdcc1bc..90b7a682c57 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -483,6 +483,8 @@ MONO_AOT_MODE_LAST = 1000, exporter.AddIosFramework("libiconv.tbd"); exporter.AddIosFramework("GSS.framework"); exporter.AddIosFramework("CFNetwork.framework"); + if (!aotOpts.UseInterpreter) + exporter.AddIosFramework("SystemConfiguration.framework"); } private static List CollectSymbols(IDictionary assemblies) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 8152acb8ad5..5c15c13a981 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -932,6 +932,10 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { cs_icalls_content.append(MEMBER_BEGIN "internal static uint cs_glue_version = "); cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n"); + // We have issues with beforefieldinit and AOT, so we use explicitly declare + // the static constructor to prevent the class from being beforefieldinit. + cs_icalls_content.append(MEMBER_BEGIN "static NativeCalls()\n" INDENT2 OPEN_BLOCK CLOSE_BLOCK_L2); + #define ADD_INTERNAL_CALL(m_icall) \ if (!m_icall.editor_only) { \ cs_icalls_content.append(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \ @@ -1031,15 +1035,18 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { cs_icalls_content.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n"); cs_icalls_content.append(INDENT2 "internal static uint cs_glue_version = "); cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n"); - cs_icalls_content.append("\n"); -#define ADD_INTERNAL_CALL(m_icall) \ - if (m_icall.editor_only) { \ - cs_icalls_content.append(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \ - cs_icalls_content.append(INDENT2 "internal extern static "); \ - cs_icalls_content.append(m_icall.im_type_out + " "); \ - cs_icalls_content.append(m_icall.name + "("); \ - cs_icalls_content.append(m_icall.im_sig + ");\n"); \ + // We have issues with beforefieldinit and AOT, so we use explicitly declare + // the static constructor to prevent the class from being beforefieldinit. + cs_icalls_content.append(MEMBER_BEGIN "static EditorNativeCalls()\n" INDENT2 OPEN_BLOCK CLOSE_BLOCK_L2); + +#define ADD_INTERNAL_CALL(m_icall) \ + if (m_icall.editor_only) { \ + cs_icalls_content.append(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \ + cs_icalls_content.append(INDENT2 "internal extern static "); \ + cs_icalls_content.append(m_icall.im_type_out + " "); \ + cs_icalls_content.append(m_icall.name + "("); \ + cs_icalls_content.append(m_icall.im_sig + ");\n"); \ } for (const List::Element *E = editor_custom_icalls.front(); E; E = E->next()) From a3722a73aa6349456da07754dd45859c4803f447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etchevery?= Date: Fri, 21 May 2021 06:25:51 +0200 Subject: [PATCH 6/6] C#+iOS: Fix crash at exit for passing NULL domain to mono_jit_cleanup --- modules/mono/mono_gd/gd_mono.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 7f8cc513528..200c839685a 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -1263,7 +1263,6 @@ GDMono::~GDMono() { project_assembly = NULL; - root_domain = NULL; scripts_domain = NULL; // Leave the rest to 'mono_jit_cleanup'