Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5.6k
[mono] Add iOS sample (AOT, arm64)#33633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
e89d83695bb6bbaf950f870366a7c849025a910b966498ef5b9886fe6d0ba97c0e57e7a71689b61663730c095708a67d8e9ab760eFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| bin/ | ||
| xcode/ | ||
| *.o | ||
| *.dll |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| cmake_minimum_required(VERSION 3.14.5) | ||
| project(HelloiOS) | ||
| # make sure "make all" is executed first | ||
| file(GLOB DLLS *.dll) | ||
| file(GLOB DLLS_AOT *.dll.o) | ||
| set(APP_RESOURCES | ||
| ${DLLS} | ||
| ) | ||
| # add the executable | ||
| add_executable( | ||
| HelloiOS | ||
| main.m | ||
| runtime.h | ||
| runtime.m | ||
| ${APP_RESOURCES} | ||
| ) | ||
| include_directories("../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/include/mono-2.0") | ||
| set_target_properties(HelloiOS PROPERTIES | ||
| MACOSX_BUNDLE TRUE | ||
| MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Plist.in | ||
| XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" | ||
| XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING "NO" | ||
| RESOURCE "${APP_RESOURCES}" | ||
| ) | ||
| # FIXME: `XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING` should not be NO | ||
| # investigate why `PALEXPORT` doesn't preserve symbols | ||
| target_link_libraries( | ||
| HelloiOS | ||
| "-framework Foundation" | ||
| "-framework UIKit" | ||
| "-framework GSS" | ||
| "-lz" | ||
| "-liconv" | ||
| "-force_load ../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/libmono.a" | ||
| "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.IO.Compression.Native.a" | ||
| "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Native.a" | ||
| "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Security.Cryptography.Native.Apple.a" | ||
| ${DLLS_AOT} | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| MONO_CONFIG=Debug | ||
| ARTIFACTS_BIN=../../../../../artifacts/bin/ | ||
| ARTIFACTS_BCL=$(ARTIFACTS_BIN)runtime/netcoreapp5.0-iOS-$(MONO_CONFIG)-arm64 | ||
| ARTIFACTS_MONO=$(ARTIFACTS_BIN)/mono/iOS.arm64.$(MONO_CONFIG) | ||
| DOTNET := $(shell cd ../../ && bash init-tools.sh | tail -1) | ||
| SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path) | ||
| # once a new library is added here (e.g. System.Console.dll) it should also be | ||
| # added in mono_ios_register_modules() (runtime.m) and both lib.dll and lib.dll.o | ||
| # should be added to xcodeproj | ||
| all: prepare | ||
| make aot-lib LIB=$(ARTIFACTS_MONO)/System.Private.CoreLib.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Runtime.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Runtime.Extensions.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Collections.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Core.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Threading.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Threading.Tasks.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Linq.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Memory.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Runtime.InteropServices.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Text.Encoding.Extensions.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/Microsoft.Win32.Primitives.dll | ||
| make aot-lib LIB=$(ARTIFACTS_BCL)/System.Console.dll | ||
| make Program.dll.o | ||
| # recompile Program.cs AOT | ||
| Program.dll.o: bin/Program.dll Makefile | ||
| make aot-lib LIB=bin/Program.dll | ||
| # we need to copy some BCL libs to ARTIFACTS_MONO | ||
| # to be able to aot other bcl libs | ||
| prepare: | ||
| cp $(ARTIFACTS_BCL)/System.Memory.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/System.Collections.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/System.Threading.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/System.Threading.Thread.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/System.Runtime.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/System.Runtime.InteropServices.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/System.Text.Encoding.Extensions.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/Microsoft.Win32.Primitives.dll $(ARTIFACTS_MONO) | ||
| cp $(ARTIFACTS_BCL)/System.Console.dll $(ARTIFACTS_MONO) | ||
| bin/Program.dll: Program.cs | ||
| $(DOTNET) build -c Debug Program.csproj | ||
| aot-lib: | ||
| DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 MONO_PATH=$(ARTIFACTS_MONO) \ | ||
| $(ARTIFACTS_MONO)/cross/./mono-aot-cross -O=gsharedvt,float32 --nollvm --debug \ | ||
| --aot=mtriple=arm64-ios,static,asmonly,direct-icalls,no-direct-calls,dwarfdebug,full $(LIB) && \ | ||
| clang -isysroot $(SYSROOT) -miphoneos-version-min=10.1 -arch arm64 -c $(LIB).s | ||
| cp $(LIB) $(notdir $(LIB)) | ||
| # generate an xcode project | ||
| xcode: all | ||
| cmake -S. -BXcode -GXcode \ | ||
| -DCMAKE_SYSTEM_NAME=iOS \ | ||
| -DCMAKE_OSX_ARCHITECTURES=arm64 \ | ||
| -DCMAKE_OSX_DEPLOYMENT_TARGET=10.1 \ | ||
| -DCMAKE_INSTALL_PREFIX=`pwd`/_install \ | ||
| -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=YES \ | ||
| -DCMAKE_IOS_INSTALL_COMBINED=YES \ | ||
| -DMONO_CONFIG=$(MONO_CONFIG) \ | ||
| -DMONO_ARCH=arm64 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| <plist version="1.0"> | ||
| <dict> | ||
| <key>CFBundleDevelopmentRegion</key> | ||
| <string>en-US</string> | ||
| <key>CFBundleExecutable</key> | ||
| <string>HelloiOS</string> | ||
| <key>CFBundleIdentifier</key> | ||
| <string>net.dot.HelloiOS</string> | ||
| <key>CFBundleInfoDictionaryVersion</key> | ||
| <string>6.0</string> | ||
| <key>CFBundleName</key> | ||
| <string>HelloiOS</string> | ||
| <key>CFBundlePackageType</key> | ||
| <string>APPL</string> | ||
| <key>CFBundleShortVersionString</key> | ||
| <string>1.0</string> | ||
| <key>CFBundleVersion</key> | ||
| <string>1</string> | ||
| <key>LSRequiresIPhoneOS</key> | ||
| <true/> | ||
| <key>UIApplicationSceneManifest</key> | ||
| <dict> | ||
| <key>UIApplicationSupportsMultipleScenes</key> | ||
| <false/> | ||
| </dict> | ||
| <key>UIRequiredDeviceCapabilities</key> | ||
| <array> | ||
| <string>arm64</string> | ||
| </array> | ||
| <key>UISupportedInterfaceOrientations</key> | ||
| <array> | ||
| <string>UIInterfaceOrientationPortrait</string> | ||
| </array> | ||
| <key>UISupportedInterfaceOrientations~ipad</key> | ||
| <array> | ||
| <string>UIInterfaceOrientationPortrait</string> | ||
| </array> | ||
| </dict> | ||
| </plist> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| using System; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
| using System.Runtime.InteropServices; | ||
| // it's not part of the BCL but runtime needs it for native-to-managed callbacks in AOT | ||
| // To be replaced with NativeCallableAttribute | ||
| public class MonoPInvokeCallbackAttribute : Attribute | ||
| { | ||
| public MonoPInvokeCallbackAttribute(Type delegateType) { } | ||
| } | ||
| public static class Program | ||
| { | ||
| // Defined in main.m | ||
| [DllImport("__Internal")] | ||
| private extern static void ios_set_text(string value); | ||
| [DllImport("__Internal")] | ||
| private extern static void ios_register_button_click(Action action); | ||
| private static Action buttonClickHandler = null; | ||
| private static int counter = 0; | ||
| // Called by native code, see main.m | ||
| [MonoPInvokeCallback(typeof(Action))] | ||
| private static async void OnButtonClick() | ||
| { | ||
| ios_set_text("OnButtonClick! #" + counter++); | ||
| } | ||
| public static async Task Main(string[] args) | ||
| { | ||
| // Register a managed callback (will be called by UIButton, see main.m) | ||
| // Also, keep the handler alive so GC won't collect it. | ||
| ios_register_button_click(buttonClickHandler = OnButtonClick); | ||
| const string msg = "Hello World!\n.NET 5.0"; | ||
| for (int i = 0; i < msg.Length; i++) | ||
| { | ||
| // a kind of an animation | ||
| ios_set_text(msg.Substring(0, i + 1)); | ||
| await Task.Delay(100); | ||
| } | ||
MemberAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is how text is animated (see gif) | ||
| // TODO: https://github.com/dotnet/runtime/issues/33667 | ||
| Console.WriteLine("Done!"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <OutputPath>bin</OutputPath> | ||
| <TargetFramework>$(NetCoreAppCurrent)</TargetFramework> | ||
| </PropertyGroup> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| #import <UIKit/UIKit.h> | ||
| #import "runtime.h" | ||
| @interface ViewController : UIViewController | ||
| @end | ||
| @interface AppDelegate : UIResponder <UIApplicationDelegate> | ||
| @property (strong, nonatomic) UIWindow *window; | ||
| @property (strong, nonatomic) ViewController *controller; | ||
| @end | ||
| @implementation AppDelegate | ||
| - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { | ||
| self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; | ||
| self.controller = [[ViewController alloc] initWithNibName:nil bundle:nil]; | ||
| self.window.rootViewController = self.controller; | ||
| [self.window makeKeyAndVisible]; | ||
| return YES; | ||
| } | ||
| @end | ||
| UILabel *label; | ||
| void (*clickHandlerPtr)(void); | ||
| @implementation ViewController | ||
| - (void)viewDidLoad { | ||
| [super viewDidLoad]; | ||
| label = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; | ||
| label.textColor = [UIColor greenColor]; | ||
| label.font = [UIFont boldSystemFontOfSize: 30]; | ||
| label.numberOfLines = 2; | ||
| label.textAlignment = NSTextAlignmentCenter; | ||
| [self.view addSubview:label]; | ||
| UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoDark]; | ||
| [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; | ||
| [button setFrame:CGRectMake(50, 300, 200, 50)]; | ||
| [button setTitle:@"Click me" forState:UIControlStateNormal]; | ||
| [button setExclusiveTouch:YES]; | ||
| [self.view addSubview:button]; | ||
| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
| mono_ios_runtime_init (); | ||
| }); | ||
| } | ||
| -(void) buttonClicked:(UIButton*)sender | ||
| { | ||
| if (clickHandlerPtr) | ||
| clickHandlerPtr(); | ||
| } | ||
| @end | ||
| // called from C# sample | ||
| void | ||
| ios_register_button_click (void* ptr) | ||
| { | ||
| clickHandlerPtr = ptr; | ||
| } | ||
| // called from C# sample | ||
| void | ||
| ios_set_text (const char* value) | ||
| { | ||
| NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; | ||
| dispatch_async(dispatch_get_main_queue(), ^{ | ||
| label.text = nsstr; | ||
| }); | ||
| } | ||
| int main(int argc, char * argv[]) { | ||
| @autoreleasepool { | ||
| return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| #ifndef runtime_h | ||
| #define runtime_h | ||
| void mono_ios_runtime_init (void); | ||
| #endif /* runtime_h */ |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great to avoid this and use
NativeCallableAttribute@vargaz could you please check where we are with the support of mono/mono#17479
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it basically same thing? but yeah
NativeCallableAttributesounds better.