Skip to content
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

[dotnet] Add support for universal apps. #11983

Merged
merged 44 commits into from
Jun 29, 2021

Conversation

rolfbjarne
Copy link
Member

@rolfbjarne rolfbjarne commented Jun 18, 2021

Add support for universal / fat apps for iOS, macOS and Mac Catalyst.

We detect if we need to build a universal app by checking if RuntimeIdentifiers (plural) is set, and in that case we do a complete inner build for every RuntimeIdentifier, and then once those inner builds are done, we merge the resulting .app bundles together (using a new MSBuild task called MergeAppBundles).

When merging app bundles together, we'll run into files that exist in both apps. Depending on the file type, we do different things:

  • MachO flies: lipo'ed together.
  • Managed assemblies: we do a binary comparison, if the assemblies are different, we put them in a RID-specific subdirectory. At runtime we know to look for assemblies in this directory.
  • runtimeconfig.bin, icudt.dat: put in a RID-specific subdirectory.
  • Info.plist: computed in the outer (fat) build, the one from the inner build is ignored.
  • Other files: for identical files we just copy one, otherwise we show an error.

If we run into files that are different between apps, but we should handle somehow, then we'll have to decide on a case-to-case basis what to do.

Some code shuffling was required to increase code sharing between the tools/ code, the msbuild/ code, and tests.

I've also added support for a default RuntimeIdentifier.

@spouliot FYI this PR incorporates most of #11320 (it was needed to resolve the location of icudt.dat at runtime).

Fixes #10294.
Fixes #10861.

This PR is best reviewed commit-by-commit.

This makes writing tests a bit easier, since we can use the same test project name
for all platforms.
…alid RuntimeIdentifier. Fixes xamarin#10861.

Also add tests:

* Remove RuntimeIdentifier from a few sample projects. These projects should
  continue to build just fine.
* Add tests for invalid RuntimeIdentifiers.

Fixes xamarin#10861.
…he outer build of a multi-rid build.

There's nothing to publish (except the merged app bundle, which we'll handle ourselves).
* Do an inner build per RuntimeIdentifier.
* In the outer build, execute the new MergeAppBundles task to
  merge the resulting app bundles from the inner builds.
It's not clear what we're supposed to do if both RuntimeIdentifier and
RuntimeIdentifiers are set, so just handle this case as if only
RuntimeIdentifiers is set, by clearing out the RuntimeIdentifier value.

Also show a warning for this scenario.
@rolfbjarne rolfbjarne added not-notes-worthy Ignore for release notes run-dotnet-tests Run all the .NET tests run-all-tests Run all our tests. skip-device-tests Skip device tests labels Jun 18, 2021
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

Add a _MapRuntimeIdentifierToTargetArchitecture target that computes the
TargetArchitectures property from either the RuntimeIdentifier or
the RuntimeIdentifiers properties.

Also make sure this target is executed before _ComputeTargetArchitectures.

This is required so that we have a correct TargetArchitectures value for
multi-rid builds when compiling the app manifest (Info.plist).
@rolfbjarne rolfbjarne changed the title [DRAFT] [dotnet] Add support for universal apps. [dotnet] Add support for universal apps. Jun 23, 2021
@rolfbjarne rolfbjarne marked this pull request as ready for review June 23, 2021 17:10
@rolfbjarne rolfbjarne requested review from emaf and spouliot as code owners June 23, 2021 17:10
Copy link
Contributor

@spouliot spouliot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

return false;
using (var reader = new BinaryReader (fs)) {
var magic = reader.ReadUInt32 ();
reader.BaseStream.Position = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why reset the position ?
as the reader is not used before being disposed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was copied from somewhere else - I'll remove this line.


internal static string Prefix {
get {
return "MSB";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we [re-]use this prefix ?


public static bool IsStaticLibrary (string filename, bool throw_if_error = false)
{
using (var fs = new FileStream (filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File.OpenRead (filename) is simpler (and identical)
https://docs.microsoft.com/en-us/dotnet/api/system.io.file.openread?view=net-5.0

throw new Exception (string.Format ("Could not readlink '{0}': {1}", path, Marshal.GetLastWin32Error ()));

return Encoding.UTF8.GetString (buffer, 0, rv);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was not that moved (in a previous commit) to share that code ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you referring to 7aec86f?

If so, this is new code (to get the target of a symlink), the code that moved was to check if a file is a symlink or not.

char *icu_dat_file_path = NULL;

char path [1024];
if (!xamarin_locate_app_resource (xamarin_icu_dat_file_name, path, sizeof (path))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks like ios-arm and ios-arm64 each as a copy of the icu data file ?
I don't recall if those are identical (or not) between architectures... but if they are then it's a big opportunity for sharing it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the icu data file is different between architectures (the arm one is bigger):

 ls -la [...]/xamarin-macios/tests/dotnet/packages/microsoft.netcore.app.runtime.mono.ios-arm*/6.0.0-preview.6.21276.13/runtimes/ios-arm*/native/icudt.dat
-rwxr--r--  1 rolf  wheel  1713152 May 18 21:54 [...]/xamarin-macios/tests/dotnet/packages/microsoft.netcore.app.runtime.mono.ios-arm/6.0.0-preview.6.21276.13/runtimes/ios-arm/native/icudt.dat
-rwxr--r--  1 rolf  wheel  1636880 May 18 21:54 [...]/xamarin-macios/tests/dotnet/packages/microsoft.netcore.app.runtime.mono.ios-arm64/6.0.0-preview.6.21276.13/runtimes/ios-arm64/native/icudt.dat

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference is unintentional. I don't think there's a tracking issue for it but I already mentioned it few times in some comments. The ICU data are generated from same input using the same tools. My theory is that there is some compression involved and the zlib library consumed by different builds is slightly different version with different defaults.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's unintended, they should be identical. Filed dotnet/runtime#55637

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I was about to file an issue and look into it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@filipnavara I wonder if ICU data for 64bit is a bit bigger due to some 64bit paddings etc for performance sake 🙂

Copy link
Contributor

@filipnavara filipnavara Jul 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EgorBo Unlikely. The arm64 ones on Android and iOS are different size (dotnet/designs#225 (comment)). I don't think it's even memory mapped so the micro-optimizations would not make much difference.

@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ [PR Build] Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

API & Generator diff

API Diff (from PR only) (no change)
Generator Diff (no change)

GitHub pages

Results can be found in the following github pages (it might take some time to publish):

Test results

3 tests failed, 218 tests passed.

Failed tests

  • monotouch-test/Mac Catalyst/Debug [dotnet]: Failed (Tests run: 2622 Passed: 2489 Inconclusive: 35 Failed: 1 Ignored: 132)
  • MSBuild tests/Tasks: Failed (Execution failed with exit code 7)
  • DotNet tests: Failed (Execution failed with exit code 1)

Pipeline on Agent XAMBOT-1098.BigSur'
Merge 7f505c3 into 1f84aaa

Fixes this error:

> error : Unable to merge the file 'Contents/Resources/MonoTouchDebugConfiguration.txt', it's different between the input app bundles.
…rms.

Fixes this error:

> Unable to merge the file 'Contents/Info.plist', it's different between the input app bundles.
* Don't use a fake target, it'll always be executed.
Returns="@(_AssemblyPublishDirectory)"
>
<ItemGroup>
<_AssemblyPublishDirectory Include="$(MSBuildProjectDirectory)/$(_AppBundlePath)">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if using full path here will work from Windows, because we'll end up passing a Windows full path to the task that will be executed on macOS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emaf I've changed this to be a relative path now.

ArchitectureSpecificFiles="@(_ArchitectureSpecificFiles)"
IgnoreFiles="Info.plist"
InputAppBundles="@(_AssemblyPublishDirectories)"
OutputAppBundle="$(MSBuildProjectDirectory)/$(_AppBundlePath)"
Copy link
Contributor

@emaf emaf Jun 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we could potentially have a similar problem here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emaf same, I've changed this to be a relative path now.

@vs-mobiletools-engineering-service2
Copy link
Collaborator

🔥 Tests failed catastrophically on Build (no summary found). 🔥

Result file $(TEST_SUMMARY_PATH) not found.

Pipeline on Agent
Merge 31b48eb into 4914136

@rolfbjarne
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

To not cause problems on Windows.
@vs-mobiletools-engineering-service2
Copy link
Collaborator

❌ [PR Build] Tests failed on Build ❌

Tests failed on Build.

API diff

✅ API Diff from stable

View API diff

API & Generator diff

API Diff (from PR only) (no change)
Generator Diff (no change)

GitHub pages

Results can be found in the following github pages (it might take some time to publish):

Test results

1 tests failed, 220 tests passed.

Failed tests

  • MSBuild tests/Tasks: Failed (Execution failed with exit code 7)

Pipeline on Agent XAMBOT-1096.BigSur'
Merge 31b48eb into 4914136

@vs-mobiletools-engineering-service2
Copy link
Collaborator

✅ [PR Build] Tests passed on Build. ✅

Tests passed on Build.

API diff

✅ API Diff from stable

View API diff

API & Generator diff

API Diff (from PR only) (no change)
Generator Diff (no change)

GitHub pages

Results can be found in the following github pages (it might take some time to publish):

🎉 All 221 tests passed 🎉

Pipeline on Agent XAMBOT-1104.BigSur'
Merge 8aff15a into 69698be

@rolfbjarne rolfbjarne merged commit ebf6c13 into xamarin:main Jun 29, 2021
@rolfbjarne rolfbjarne deleted the dotnet-multi-rid branch June 29, 2021 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
not-notes-worthy Ignore for release notes run-all-tests Run all our tests. run-dotnet-tests Run all the .NET tests skip-device-tests Skip device tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Default RuntimeIdentifier .NET 6: add support for builds with multiple architectures (fat apps)
8 participants