Skip to content

Commit ef81785

Browse files
Merge pull request #43735 from dotnet/main
Merge main into live
2 parents 126855c + 6b2c951 commit ef81785

File tree

6 files changed

+311
-10
lines changed

6 files changed

+311
-10
lines changed
184 KB
Loading
230 KB
Loading

docs/core/deploying/native-aot/index.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,11 @@ The following table shows supported compilation targets.
152152
| Windows | x64, Arm64 | |
153153
| Linux | x64, Arm64 | |
154154
| macOS | x64, Arm64 | |
155-
| iOS | Arm64 | Experimental support |
156-
| iOSSimulator | x64, Arm64 | Experimental support |
157-
| tvOS | Arm64 | Experimental support |
158-
| tvOSSimulator | x64, Arm64 | Experimental support |
159-
| MacCatalyst | x64, Arm64 | Experimental support |
155+
| [iOS](./ios-like-platforms/index.md) | Arm64 | Experimental support |
156+
| [iOSSimulator](./ios-like-platforms/index.md) | x64, Arm64 | Experimental support |
157+
| [tvOS](./ios-like-platforms/index.md) | Arm64 | Experimental support |
158+
| [tvOSSimulator](./ios-like-platforms/index.md) | x64, Arm64 | Experimental support |
159+
| [MacCatalyst](./ios-like-platforms/index.md) | x64, Arm64 | Experimental support |
160160
| Android | x64, Arm64 | Experimental, no built-in Java interop |
161161

162162
### [.NET 9+](#tab/net9plus)
@@ -166,11 +166,13 @@ The following table shows supported compilation targets.
166166
| Windows | x64, Arm64, x86 | |
167167
| Linux | x64, Arm64, Arm | |
168168
| macOS | x64, Arm64 | |
169-
| iOS | Arm64 | |
170-
| iOSSimulator | x64, Arm64 | |
171-
| tvOS | Arm64 | |
172-
| tvOSSimulator | x64, Arm64 | |
173-
| MacCatalyst | x64, Arm64 | |
169+
| [iOS](./ios-like-platforms/index.md) | Arm64 | |
170+
| [iOSSimulator](./ios-like-platforms/index.md) | x64, Arm64 | |
171+
| [tvOS](./ios-like-platforms/index.md) | Arm64 | |
172+
| [tvOSSimulator](./ios-like-platforms/index.md) | x64, Arm64 | |
173+
| [MacCatalyst](./ios-like-platforms/index.md) | x64, Arm64 | |
174174
| Android | x64, Arm64, Arm | Experimental, no built-in Java interop |
175175

176176
---
177+
178+
For more information about how specific platform is supported with Native AOT, follow the link from the table.
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
---
2+
title: Create and consume custom frameworks for iOS-like platforms
3+
description: How to create and consume custom frameworks with Native AOT for iOS-like platforms
4+
author: ivanpovazan
5+
ms.author: ivanpovazan
6+
ms.date: 11/21/2024
7+
---
8+
9+
# Create and consume custom frameworks for iOS-like platforms
10+
11+
Starting from .NET 9, Native AOT supports publishing .NET class libraries that don't depend on iOS workloads for iOS-like platforms.
12+
This support enables you to create self-contained native libraries that can be consumed from iOS, Mac Catalyst, and tvOS applications.
13+
14+
> [!IMPORTANT]
15+
> This approach does not come with the built-in Objective-C interoperability support and additional code adaptations might be required (such as marshalling reference type arguments) to achieve interoperability.
16+
17+
## Build shared libraries
18+
19+
This section describes steps to create a simple .NET Class Library project with NativeAOT support and produce a native library for iOS-like platforms from it.
20+
21+
1. Download .NET 9 SDK
22+
2. Create a class library project
23+
24+
```bash
25+
dotnet new classlib -n "MyNativeAOTLibrary"
26+
```
27+
28+
3. Add the following properties into the project file `MyNativeAOTLibrary.csproj`
29+
30+
```xml
31+
<PublishAot>true</PublishAot>
32+
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
33+
```
34+
35+
4. Edit the `MyNativeAOTLibrary/Class1.cs` source code to expose a managed method so that it can be referenced from the native code as `aotsample_add`. For example:
36+
37+
```cs
38+
using System.Runtime.InteropServices;
39+
namespace NaotLib;
40+
41+
public class Class1
42+
{
43+
[UnmanagedCallersOnly(EntryPoint = "aotsample_add")]
44+
public static int Add(int a, int b)
45+
{
46+
return a + b;
47+
}
48+
}
49+
```
50+
51+
5. Publish the class library and target the desired iOS-like platform by specifying the appropriate runtime identifier (referenced below as `<rid>`):
52+
53+
```bash
54+
dotnet publish -r <rid> MyNativeAOTLibrary/MyNativeAOTLibrary.csproj
55+
```
56+
57+
Successful completion of the previous step produces a pair of files: a shared library `MyNativeAOTLibrary.dylib` and its debug symbols `MyNativeAOTLibrary.dylib.dSYM`, which are located at: `MyNativeAOTLibrary/bin/Release/net9.0/<rid>/publish/`.
58+
59+
> [!NOTE]
60+
> For creating universal frameworks, it is required to publish the class library for both `Arm64` and `x64` architectures for a given platform.
61+
> This means that you need to repeat step 5 with a different runtime identifier.
62+
> For example, you'd publish the class library with both `maccatalyst-arm64` and `maccatalyst-x64` runtime identifiers as a prerequisite for [Packaging the shared library into a custom MacCatalyst universal framework](#package-the-shared-library-into-a-custom-maccatalyst-universal-framework).
63+
64+
## Create and consume a custom framework
65+
66+
Apple imposes a requirement that shared libraries (.dylibs) need to be packaged into frameworks in order to be consumed from applications.
67+
68+
This section describes all required steps to achieve this and a simple scenario of a iOS/MacCatalyst application consuming a shared NativeAOT library/framework.
69+
70+
> [!NOTE]
71+
> The described steps are just for demonstration purposes. The actual requirements might differ depending on the exact use case.
72+
73+
### Package the shared library into custom iOS framework
74+
75+
1. Create a framework folder:
76+
77+
```bash
78+
mkdir MyNativeAOTLibrary.framework
79+
```
80+
81+
2. Adjust load commands:
82+
83+
- `LC_RPATH` load command
84+
85+
```bash
86+
install_name_tool -rpath @executable_path @executable_path/Frameworks MyNativeAOTLibrary/bin/Release/net9.0/ios-arm64/publish/MyNativeAOTLibrary.dylib
87+
```
88+
89+
- `LC_ID_DYLIB` load command
90+
91+
```bash
92+
install_name_tool -id @rpath/MyNativeAOTLibrary.framework/MyNativeAOTLibrary MyNativeAOTLibrary/bin/Release/net9.0/ios-arm64/publish/MyNativeAOTLibrary.dylib
93+
```
94+
95+
3. Manually package the binary into a universal file:
96+
97+
```bash
98+
lipo -create MyNativeAOTLibrary/bin/Release/net9.0/ios-arm64/publish/MyNativeAOTLibrary.dylib -output MyNativeAOTLibrary.framework/MyNativeAOTLibrary
99+
```
100+
101+
4. Add a property list file to your framework:
102+
103+
- Create a `Info.plist` file
104+
105+
```bash
106+
touch MyNativeAOTLibrary.framework/Info.plist
107+
```
108+
109+
- Add the contents from the [appendix](#appendix-infoplist-contents) into the created `Info.plist` file
110+
111+
After the final step, the framework structure should look like this:
112+
113+
```
114+
MyNativeAOTLibrary.framework
115+
|_ MyNativeAOTLibrary
116+
|_ Info.plist
117+
```
118+
119+
### Package the shared library into a custom MacCatalyst universal framework
120+
121+
Universal frameworks require binaries for both `Arm64` and `x64` architecture.
122+
For this reason, you must publish native libraries targeting both of the following RIDs beforehand: `maccatalyst-arm64` and `maccatalyst-x64`.
123+
124+
1. Create a framework folder structure:
125+
126+
```bash
127+
mkdir -p MyNativeAOTLibrary.framework/Versions/A/Resources
128+
ln -sfh Versions/Current/MyNativeAOTLibrary MyNativeAOTLibrary.framework/MyNativeAOTLibrary
129+
ln -sfh Versions/Current/Resources MyNativeAOTLibrary.framework/Resources
130+
ln -sfh A MyNativeAOTLibrary.framework/Versions/Current
131+
```
132+
133+
2. Adjust load commands:
134+
135+
- `LC_RPATH` load command
136+
137+
```bash
138+
install_name_tool -rpath @executable_path @executable_path/../Frameworks MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-arm64/publish/MyNativeAOTLibrary.dylib
139+
install_name_tool -rpath @executable_path @executable_path/../Frameworks MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-x64/publish/MyNativeAOTLibrary.dylib
140+
```
141+
142+
- `LC_ID_DYLIB` load command
143+
144+
```bash
145+
install_name_tool -id @rpath/MyNativeAOTLibrary.framework/Versions/A/MyNativeAOTLibrary MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-arm64/publish/MyNativeAOTLibrary.dylib
146+
install_name_tool -id @rpath/MyNativeAOTLibrary.framework/Versions/A/MyNativeAOTLibrary MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-x64/publish/MyNativeAOTLibrary.dylib
147+
```
148+
149+
3. Manually package the binary into a universal file:
150+
151+
```bash
152+
lipo -create MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-arm64/publish/MyNativeAOTLibrary.dylib MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-x64/publish/MyNativeAOTLibrary.dylib -output MyNativeAOTLibrary.framework/Versions/A/MyNativeAOTLibrary
153+
```
154+
155+
4. Add a property list file to your framework:
156+
157+
- Create a `Info.plist` file
158+
159+
```bash
160+
touch MyNativeAOTLibrary.framework/Versions/A/Resources/Info.plist
161+
```
162+
163+
- Add the contents from the [appendix](#appendix-infoplist-contents) into the created `Info.plist` file
164+
165+
After the final step, the framework structure should look like this:
166+
167+
```
168+
MyNativeAOTLibrary.framework
169+
|_ MyNativeAOTLibrary -> Versions/Current/MyNativeAOTLibrary
170+
|_ Resources -> Versions/Current/Resources
171+
|_ Versions
172+
|_ A
173+
| |_ Resources
174+
| | |_ Info.plist
175+
| |_ MyNativeAOTLibrary
176+
|_ Current -> A
177+
```
178+
179+
### Consume custom frameworks
180+
181+
1. Open `Xcode` (in this example `Xcode 16.0` is used)
182+
2. Create a new `App` project
183+
3. Choose the name for your app (for example, `MyiOSApp`) and choose Objective-C as the source language
184+
4. Add a reference to the `MyNativeAOTLibrary` framework
185+
- In the `MyiOSApp` targets **General** tab, under **Frameworks, Libraries and Embedded Content**, select **+** to add `MyNativeAOTLibrary` as the referenced framework
186+
- In the dialog, choose **Add Other** -> **Add Files** and then browse to the location of `MyNativeAOTLibrary.framework` and select it
187+
- Once selected, set `Embed and Sign` option for `MyNativeAOTLibrary` framework
188+
189+
![Xcode add framework reference](../../media/native-aot-ios-like-platforms/xcode-add-framework-reference.png)
190+
191+
5. Add `MyNativeAOTLibrary.framework` location to the list of **Framework Search Paths** in the **Build Settings** tab
192+
193+
![Xcode add framework search path](../../media/native-aot-ios-like-platforms/xcode-add-framework-search-path.png)
194+
195+
6. Edit `main.m` by calling the exposed managed method `aotsample_add` and printing the result
196+
197+
```objc
198+
extern int aotsample_add(int a, int b);
199+
int main(int argc, char * argv[]) {
200+
...
201+
NSLog(@"2 + 5 = %d", aotsample_add(2, 5));
202+
...
203+
}
204+
```
205+
206+
7. Select your physical iOS device and build/run the app
207+
8. Inspect the logs after the app has successfully launched. The app should print out: `2 + 5 = 7`
208+
209+
> [!NOTE]
210+
> For MacCatalyst, use the same steps except for step 7, where the Run Destination needs to be set as: `Mac (Mac Catalyst)`.
211+
212+
## Build static libraries with NativeAOT for iOS-like platforms
213+
214+
As described in [building native libraries overview](../libraries.md#building-native-libraries), it's better to build shared libraries over static ones due to several limitations.
215+
216+
However, if desired, you can build a static library by following the steps for building a shared one and including an additional property in the project file:
217+
218+
```xml
219+
<NativeLib>Static</NativeLib>
220+
```
221+
222+
After the project has been published, the static library `MyNativeAOTLibrary.a` can be found at: `MyNativeAOTLibrary/bin/Release/net9.0/<rid>/publish`.
223+
224+
This article doesn't cover how to consume the static library and configure the consumer project.
225+
226+
## Appendix Info.plist contents
227+
228+
```xml
229+
<?xml version="1.0" encoding="UTF-8"?>
230+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
231+
<plist version="1.0">
232+
<dict>
233+
<key>CFBundleName</key>
234+
<string>MyNativeAOTLibrary</string>
235+
<key>CFBundleIdentifier</key>
236+
<string>com.companyname.MyNativeAOTLibrary</string>
237+
<key>CFBundleVersion</key>
238+
<string>1.0</string>
239+
<key>CFBundleExecutable</key>
240+
<string>MyNativeAOTLibrary</string>
241+
<key>CFBundlePackageType</key>
242+
<string>FMWK</string>
243+
</dict>
244+
</plist>
245+
```
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: Native AOT support for iOS-like platforms overview
3+
description: Learn how Native AOT supports iOS-like platforms
4+
author: ivanpovazan
5+
ms.author: ivanpovazan
6+
ms.date: 11/21/2024
7+
---
8+
9+
# Native AOT support for iOS-like platforms
10+
11+
Starting from .NET 9, Native AOT supports targeting iOS-like platforms. The term *iOS-like platforms* refers to Apple platforms that use similar APIs such as: iOS, MacCatalyst and tvOS.
12+
13+
Based on the use case, the support can be divided into:
14+
15+
- support for applications and libraries referencing OS-specific APIs
16+
- support for applications and libraries without OS-specific API dependencies
17+
18+
## Support for applications and libraries referencing OS-specific APIs
19+
20+
This refers to .NET MAUI projects targeting OS-specific target frameworks (like: `net9.0-ios`).
21+
How Native AOT can be enabled for .NET MAUI apps, see [Native AOT deployment on iOS and Mac Catalyst](/dotnet/maui/deployment/nativeaot).
22+
23+
## Support for applications and libraries without OS-specific API dependencies
24+
25+
This refers to .NET projects targeting the general or non-OS-specific target framework (like: `net9.0`), for which Native AOT can be enabled in the following way:
26+
27+
1. Include the following properties in your project file:
28+
29+
```xml
30+
<PublishAot>true</PublishAot>
31+
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
32+
```
33+
34+
2. Publish the project for the desired iOS-like target platform by specifying adequate runtime identifier (later referred to as `<rid>`):
35+
36+
- `ios-arm64`, for iOS physical devices
37+
- `iossimulator-arm64` or `iossimulator-x64`, for iOS simulators
38+
- `maccatalyst-arm64` or `maccatalyst-x64`, for Mac Catalyst
39+
- `tvos-arm64`, for tvOS physical devices
40+
- `tvossimulator-arm64` or `tvossimulator-x64`, for tvOS simulators
41+
42+
and execute the following command:
43+
44+
```
45+
dotnet publish -r <rid>
46+
```
47+
48+
For specifics of building and consuming native libraries on iOS-like platforms, see [How to create and consume custom frameworks with Native AOT for iOS-like platforms](./creating-and-consuming-custom-frameworks.md).

docs/navigate/devops-testing/toc.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,12 @@ items:
539539
href: ../../core/deploying/native-aot/warnings/il3055.md
540540
- name: IL3056
541541
href: ../../core/deploying/native-aot/warnings/il3056.md
542+
- name: iOS-like platforms
543+
items:
544+
- name: Overview
545+
href: ../../core/deploying/native-aot/ios-like-platforms/index.md
546+
- name: Create and consume custom frameworks
547+
href: ../../core/deploying/native-aot/ios-like-platforms/creating-and-consuming-custom-frameworks.md
542548
- name: Runtime package store
543549
href: ../../core/deploying/runtime-store.md
544550
- name: Runtime Identifier (RID) catalog

0 commit comments

Comments
 (0)