简体   繁体   中英

Xamarin.iOS builds, most notably Linking and AOT-compilation, take over 2 minutes in debug configurations

I have a Xamarin.iOS project (as part of a cross-platform solution) which has grown quite a bit over time. However, only the iOS build take such a substantial amount of time (Windows Desktop builds take a few seconds while Android takes rarely over 30 seconds, from which 24 seconds are the install process). After a lot of tweaking I could reduce the build time to about 02:21 for iOS devices/simulators, which is still far beyond convenient for debugging.

Here is the project file that achieves this time:

<Project Sdk="Microsoft.NET.Sdk">
    
    <PropertyGroup>
        <TargetFramework>net6.0-ios</TargetFramework>
        <SingleProject>true</SingleProject>
        <OutputType>Exe</OutputType>
        <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
        <IsUnoHead>true</IsUnoHead>
        <SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
        <Nullable>enable</Nullable>
        <UseMauiEssentials>True</UseMauiEssentials>
        <ProvisioningType>manual</ProvisioningType>
        <MtouchInterpreter>-all</MtouchInterpreter>
    </PropertyGroup>

    <PropertyGroup>
        <MtouchExtraArgs>$(MtouchExtraArgs) --setenv=MONO_GC_PARAMS=soft-heap-limit=512m,nursery-size=64m,evacuation-threshold=66,major=marksweep,concurrent-sweep</MtouchExtraArgs>
        <MtouchExtraArgs>$(MtouchExtraArgs) --marshal-objectivec-exceptions:disable</MtouchExtraArgs>
        <MtouchExtraArgs>$(MtouchExtraArgs) --marshal-managed-exceptions:default</MtouchExtraArgs>
        <MtouchExtraArgs>$(MtouchExtraArgs) --registrar:static</MtouchExtraArgs>
        <MtouchExtraArgs>$(MtouchExtraArgs) --time --time</MtouchExtraArgs>
        <MtouchExtraArgs>$(MtouchExtraArgs) -v -v -v -v</MtouchExtraArgs>
    </PropertyGroup>

    <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
        <MtouchLink>Full</MtouchLink>
        <Optimize>false</Optimize>
    </PropertyGroup>
    
    <PropertyGroup Condition="'$(Configuration)' != 'Debug'">
        <MtouchUseLlvm>true</MtouchUseLlvm>
        <MtouchLink>SdkOnly</MtouchLink>
        <BuildIpa>true</BuildIpa>
        <Optimize>true</Optimize>
        <CodesignKey>***</CodesignKey>
        <CodesignProvision>***</CodesignProvision>
    </PropertyGroup>
    
    <ItemGroup>
<!--project references-->
    </ItemGroup>
    
</Project>

Environment:

  • Visual Studio 22 (17.4.3) on a Windows 11 machine;
  • connecting remotely to a Mac Mini 2018 running Xcode 14.2;
  • Xamarin.iOS 16.1.1.27

The issue has neither changed for the worse nor better on respective older releases of any of these though.

Building directly from the Mac grants no notable improvement compared to the remote build through Visual Studio.

I tried tampering with some project properties to achieve the lowest build time possible:

  1. MtouchLink
  • Setting 'SdkOnly' or 'Full' does not make as much of a difference as anticipated. The former boosts the build time about up to 10 seconds when running on a physical device. On the Simulator the total build time is generally unchanged. This is surprising to me considering the elapsed time required for ILLink (see below).
  • Setting 'None' does not work as it results in a Failed to AOT compile Microsoft.iOS.dll, the AOT compiler exited with code 134 error.
  1. MtouchInterpreter
  • When disabled, type generics cause errors at runtime, but enabling it has no measurable bearing on the build time anyway.
  1. MtouchUseLlvm
  • I use this for release builds only as it increases the build to over 10 minutes (which is bearable for occasional release builds).

Omitting some or all of the MtouchExtraArgs did not help either.

There are some task that take more that take up most of the time to the binlog:

  • Target_UnpackLibraryResources (~3s);
  • Target_CoreCompile (~3s);
  • Target_FindAotCompiler (~4s);
  • Target_RunILLink (~46s, ~53s with SdkOnly), almost completely dedicated to Xamarin.iOS.Task.ILLink;
  • Target_AOTCompile (~52s) with CompileNativeCode taking ~38s;
  • Target_CompileNativeExecutable (~3s);
  • Target_GenerateDSym (~5s);
  • Target_SayGoodbye (~7s)

AOT is used by default in Xamarin.iOS : there is a security restriction on iOS, set by Apple, which disallows the execution of dynamically generated code on a device. To ensure that we adhere to these safety protocols, Xamarin.iOS instead uses an Ahead of Time (AOT) compiler to compile the managed code.

AOT compilation is an optimization technique used to improve startup performance, but it can also affect the build time of your app. Introduced in the Xamarin AOT documentation :

Build Time – AOT compilation is significantly slower that JIT and will slow builds using it. This slowdown can range from seconds up to a minute or more, depending on the size and number of assemblies compiled.

Linking Xamarin.iOS Apps documentation describes (This is also what makes it take longer to build):

The linker uses static analysis to determine the different code paths that your application is acceptable to follow. It's a bit heavy as it has to go through every detail of each assembly, to make sure that nothing discoverable is removed. It is not enabled by default on the simulator builds to speed up the build time while debugging.

You can try to close Visual Studio then delete bin and obj from your project, this will alleviate the problem of slow build. For more information, you can refer to: iOS Build Mechanics

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM