Commit f93a246
committed
chore: Introductory support for Native AOT builds
Context: unoplatform/uno@559b1f7
Context: unoplatform/uno.toolkit.ui@3ef6d6c
Context: unoplatform/ShowMeTheXAML#30
What do we want? To build and run with Native AOT!
Which in turn requires Uno.Sdk 6.6.0 or later:
sed -i '' 's/"Uno.Sdk": ".*"/"Uno.Sdk": "6.6.0-dev.15"/g' global.json
dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
-bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
-p:PublishAot=true
…which promptly fails to build:
…Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(120,5): error NETSDK1207:
Ahead-of-time compilation is not supported for the target framework.
~~ Build Support for Native AOT ~~
This specifically happens because `Uno.Gallery.csproj` has a
`@(ProjectReference)` to `Uno.Gallery.SourceGenerators.csproj`, which
is a .NET Standard 2.0 project, which doesn't support Native AOT.
To fix this, we need an "indirection": a property which we can set on
the command-line which causes `$(PublishAot)` to be set.
The "conventional" indirection used in unoplatform/uno SamplesApp and
in unoplatform/uno.chefs is `$(SkiaPublishAot)`. This allows:
dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
-bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true \
-p:SkiaPublishAot=true \
-p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen
which *builds* successfully. (It doesn't *run* successfully yet;
that's for later.)
~~ Build Support for Android + Native AOT ~~
Remove `$(RunAOTCompilation)` from the Android build, as it's
presence prevents use of Native AOT on Android:
/usr/local/share/dotnet/packs/Microsoft.Android.Sdk.Darwin/36.1.12/targets/Microsoft.Android.Sdk.Aot.targets(123,5): error
Precompiling failed for …/Uno.Gallery/obj/Release/net10.0-android/android-x64/aot-in/System.Collections.dll with exit code 134.
Runtime critical type System.RuntimeMethodHandle not found
# and 24 more similar errors
~~ Build Support for Mobile Side-by-Side Installation ~~
Additionally, to "reasonably easily" support side-by-side execution
of Uno Gallery builds on e.g. iOS or Android, introduce support for
the following MSBuild properties (also done in unoplatform/uno.chefs):
* `$(ApplicationIdVendorSuffix)`: Value to append to
`$(ApplicationId)`, so that separate builds have separate names.
* `$(ApplicationTitleVendorSuffix)`: Value to append to
`$(ApplicationTitle)`, so that the different builds are
distinguishable on app launchers.
On iOS, this allows side-by-side installs, but the iOS build doesn't
use the `$(ApplicationTitle)` value. This is because
`Uno.Gallery/Platforms/iOS/Info.plist` already had a
`CFBundleDisplayName` entry, which overrides `$(ApplicationTitle)`.
Remove the `CFBundleDisplayName` entry so that `$(ApplicationTitle)`
can be used to control `CFBundleDisplayName`.
~~ Desktop Startup Timing ~~
Introduce a trivial "hack" to support app starting time comparisons:
add a `--exit` command-line argument which causes the app to `Exit()`
at the end of `App.OnLaunched()`. This allows using **time**(1) to
capture "app startup time":
# CoreCLR:
% dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
-bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true
% time Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit
Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit 1.08s user 0.32s system 70% cpu 1.982 total
# Native AOT:
% dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop \
-bl Uno.Gallery/Uno.Gallery.csproj -p:UseSkiaRendering=true -p:SelfContained=true -p:SkiaPublishAot=true
% time Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit
Uno.Gallery/bin/Release/net10.0-desktop/osx-x64/publish/Uno.Gallery --exit 0.27s user 0.15s system 51% cpu 0.811 total
Or on Windows:
Measure-Command { .\Uno.Gallery\bin\Release\net10.0-desktop\win-x64\publish\Uno.Gallery.exe --exit | Out-Default } | Select TotalMilliseconds
~~ iOS Startup Timing ~~
No changes are needed; to capture startup time on iOS:
1. Install the `.ipa` onto your iOS device.
2. Open **Instruments** (launch Xcode, then
click Xcode > Open Developer Tool > Instruments)
3. In Instruments, click File > New ⌘N.
4. In the **Choose a Template…** window, select **App Launch**.
5. In the Window which appears, in the central area is a **Target**
section; from the **Device** dropdown, select your connected iOS
device, and from the **Target** dropdowns, select **Launch** and
the Uno Gallery app from the dropdown.
Note: the Target dropdown shows `CFBundleExecutable` -- which is
identical regardless of `$(ApplicationIdVendorSuffix)` or
`$(ApplicationTitleVendorSuffix)` -- so this is easiest to do if
there is only *one* Uno.Gallery app installed.
6. Click File > Record Trace ⌘R to start recording, which will launch
the app on the device.
7. When the app has finished launching, force-quit the app.
Instruments will now start processing the data.
8. Type ⌘4 to switch to **App Lifecycle**. This shows a table of
events with Start, Duration, and Narrative columns.
Look for the *Launching - Initial Frame Rendering* Narrative entry.
The Start value is the time taken to launch the app.
| Start | Duration | Narrative |
| ------------: | --------: | :------------------------------------------------ |
| 00:00.000.000 | 480.77 ms | The system took 480.77 ms to create the process. |
| … | … | … |
| 00:01.306.446 | 4.41 ms | Launching – Initial Frame Rendering |
In this run, app startup time was 1.306 seconds.
~~ Native AOT Runtime Fixes ~~
Begin fixing some of the runtime issues with Native AOT builds.
The following messages would appear on the Console during startup:
fail: Uno.Gallery.Sample[0]
Failed to initialize data for `AutoSuggestBoxSamplePage`. dataType: Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel. Exception: System.MissingMethodException: No parameterless constructor defined for type 'Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel'.
at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x180
at Uno.Gallery.Sample.CreateData(Type) + 0x3a
fail: Uno.Gallery.Sample[0]
Failed to initialize data for `BarometerSamplePage`. dataType: BarometerSamplePageViewModel. Exception: System.MissingMethodException: No parameterless constructor defined for type 'BarometerSamplePageViewModel'.
at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x180
at Uno.Gallery.Sample.CreateData(Type) + 0x3a
Plus 19 more similar messages.
These `fail` messages appear because of missing "reflection metadata"
(unoplatform/uno@559b1f78), and we can fix these by using the
`[DynamicallyAccessedMembers]` and `[DynamicDependency]` attributes.
In order to use `[DynamicallyAccessedMembers]`, we need either a
generic type parameter or a `typeof()` expression. Searching around,
there are useful places `typeof()` is already used; from
`Uno.Gallery.SourceGenerators` generated output, in
`$(CompilerGeneratedFilesOutputPath)`, we have:
// …/App.Samples.g.cs
public partial class App {
public static Sample[] GetSamples()
{
return new[] {
// …
new global::Uno.Gallery.Sample(new global::Uno.Gallery.SamplePageAttribute(category: (global::Uno.Gallery.SampleCategory)(2), title: "AutoSuggestBox", source: (global::Uno.Gallery.SourceSdk)(0), glyph: "") { Description = @"Represents a text control that makes suggestions to users as they enter text.", DocumentationLink = "https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.autosuggestbox?view=windows-app-sdk-1.3", DataType = typeof(global::Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePageViewModel), SortOrder = 2147483647 }, typeof(Uno.Gallery.Views.Samples.AutoSuggestBoxSamplePage)),
// …
};
}
}
Which has the handy benefit of containing *both*
`AutoSuggestBoxSamplePage` and `AutoSuggestBoxSamplePageViewModel`,
which were mentioned in the `fail` message.
This in turn makes the fix straightforward: update the `Sample` and
`SamplePageAttribute` types to use `[DynamicallyAccessedMembers]` on
their respective `Type` parameters and properties to preserve
constructors (from the original message) and properties, which almost
certainly will be needed anyway.
(Property preservation is reflexive at this point.)
If you select **UI components > AutoSuggestBox** in the left-side
tree view, then click the `<>` "Show XAML" button, nothing is shown
*and* the following messages are written to the Console:
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [ShowMeTheXAML:XamlDisplayExtensions.Header] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [ShowMeTheXAML:XamlDisplayExtensions.Description] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [ShowMeTheXAML:XamlDisplayExtensions.Options] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [ShowMeTheXAML:XamlDisplayExtensions.PrettyXaml] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [ShowMeTheXAML:XamlDisplayExtensions.ShowXaml] property getter does not exist on type [ShowMeTheXAML.XamlDisplay]
This is because WPF Attached Properties require use of
`[DynamicDependency]` to ensure that the required methods are
accessible via Reflection; see also unoplatform/uno.toolkit.ui@3ef6d6ce.
Update all use of `DependencyProperty.RegisterAttached()` so that
required methods are retained.
Unfortunately, while this fixes the above `fail` messages, clicking
the `<>` "Show XAML" button still does nothing.
Fixing the `<>` "Show XAML" button requires
unoplatform/ShowMeTheXAML#30 and replacing the existing
`XamlDisplay.Init()` invocation with `XamlDictionary.Init()`.
Bump to Uno.ShowMeTheXAML 2.0.0-dev0026 to get this fix, and bump
`Uno.Sdk` within `global.json` to `6.4.58` so that things still build.
If you select **UI components > BreadcrumbBar** in the left-side
tree view, then the **BreadcrumbBar with Custom DataTemplate**
section on the right-hand page doesn't show anything, and Console
output contains:
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [Name] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [ItemCount] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [Description] property getter does not exist on type [Uno.Gallery.Entities.Data.Folder]
Fix this by adding `[Microsoft.UI.Xaml.Data.Bindable]` to
`Uno.Gallery.Entities.Data.Folder`. The use of `[Bindable]` causes
the `Uno.UI.SourceGenerators.BindableTypeProvider` source generator
to emit `BindableType(…, typeof(Folder))` to `BindableMetadata.g.cs`,
which cause all public properties to be added to reflection metadata.
Add `[Bindable]` to all other types containing properties within
`Uno.Gallery.Entities.Data`. This fixes a number of other samples
and messages such as:
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [Color] property getter does not exist on type [Uno.Gallery.Entities.Data.Record]
If you select **UI features > Binding** in the left-side
tree view, the right-hand panel would be subtly different between
CoreCLR and Native AOT:
* CoreCLR: `The length is: [empty]`
* Native AOT: `The length is:`
Worse, if you enter text into "myTextBox", the bound fields properly
update under CoreCLR. For example, enter "123" into "myTextBox",
and CoreCLR would show:
> The text of myTextBox is: 123
> The length is: 3
Under Native AOT, *nothing* updates.
Console output contains:
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [Text] property getter does not exist on type [Uno.Gallery.Views.Samples.BindingSamplePageViewModel]
fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
The [TextLength] property getter does not exist on type [Uno.Gallery.Views.Samples.BindingSamplePageViewModel]
Fix this by adding `[Bindable]` to `BindingSamplePageViewModel`.
(Which means "just add `[Bindable]`!" is quickly becoming my favorite
answer to everything. Unless the type has `required` or `init`-only
properties; see also unoplatform/uno.chefs@06f4f804.)
Continue this pattern: update all types which implement
`INotifyPropertyChanged` or inherit from a type which implements
`INotifyPropertyChanged` to have `[Bindable]`. This fixes the
following `fail` messages, among others:
The [AccelerationX] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [AccelerationY] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [AccelerationZ] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [AccelerometerAvailable] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedAccuracy] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedAltitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedLatitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedLongitude] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [GeolocatedTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]
The [LastReadTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [LastShakeTimestamp] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ListenButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.ClipboardSamplePageViewModel]
The [Message] property getter does not exist on type [Uno.Gallery.Views.Samples.ClipboardSamplePageViewModel]
The [ReportInterval] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ShakeCount] property getter does not exist on type [Uno.Gallery.Views.Samples.AccelerometerSamplePageViewModel]
The [ToggleButtonContent] property getter does not exist on type [Uno.Gallery.Views.Samples.GeolocatorSamplePageViewModel]1 parent 224b77d commit f93a246
File tree
47 files changed
+137
-22
lines changed- Uno.Gallery
- Entities
- Data
- Extensions
- Platforms/iOS
- ViewModels
- Views/SamplePages
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
47 files changed
+137
-22
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
19 | | - | |
| 18 | + | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
74 | 79 | | |
75 | 80 | | |
76 | 81 | | |
| |||
486 | 491 | | |
487 | 492 | | |
488 | 493 | | |
489 | | - | |
| 494 | + | |
490 | 495 | | |
491 | 496 | | |
492 | 497 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
45 | 46 | | |
46 | 47 | | |
47 | 48 | | |
| |||
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| 55 | + | |
54 | 56 | | |
55 | 57 | | |
56 | 58 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
17 | 22 | | |
18 | 23 | | |
19 | 24 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| 34 | + | |
33 | 35 | | |
34 | 36 | | |
35 | 37 | | |
| |||
0 commit comments