From the "how did I miss it?!" department.
The main purpose of this commit is to fix parsing of the
`mono_log_mask` component of the `debug.mono.log` property.
The component is set to a list of Mono logging categories (e.g. `asm`,
`gc` or `dll`) which, so far, was supposed to be a comma-separated
list.
However… `debug.mono.log` *itself* uses commas to separate components,
so using the following:
$ adb shell setprop debug.mono.log mono_log_mask=asm,gc,dll
would *not* set the `$MONO_LOG_MASK` environment variable to the
expected value of `asm,gc,dll`, but would instead it would end up being
just `asm`, as the other values would be considered to be
`debug.mono.log` components instead.
To fix this, change the `mono_log_mask` separator to `:`, so that
we would now use:
$ adb shell setprop debug.mono.log mono_log_mask=asm:gc:dll
Additionally, document all the `debug.mono.*` properties and remove
the `DEBUG_MONO_GDBPORT_PROPERTY` constant, since it's not used
anywhere.
Also, when `assembly` or `gc` logging is enabled, we now set the Mono
tracing level to `info` instead of the default `error`. This makes
tracking assembly loader and garbage collector issues easier by
showing more info from the Mono runtime, not just from Xamarin.Android.
What do we want? Faster (Release) App Startup!
How do we get that? Assembly Stores!
"In the beginning", assemblies were stored in the `assemblies`
directory within the `.apk`. App startup would open the `.apk`,
traverse all entries within the `.apk` looking for `assemblies/*.dll`,
`assemblies/*.dll.config`, and `assemblies/*.pdb` files. When a
"supported" `assemblies/*` entry was encountered, the entry would be
**mmap**(2)'d so that it could be used; see also commit c1956835bd.
Of particular note is:
1. The need to enumerate *all* entries within the `.apk`, as there
is no guarantee of entry ordering, and
2. The need for *N* `mmap()` invocations, one per assembly included
in the app, *plus* additional `mmap()` invocations for the `.pdb`
and `.dll.config` files, if present.
Useful contextual note: a "modern" AndroidX-using app could pull
in dozens to over 200 assemblies without really trying.
There will be *lots* of `mmap()` invocations.
Instead of adding (compressed! d236af54) data for each assembly
separately, instead add a small set of "Assembly Store" files which
contain the assembly & related data to use within the app:
* `assemblies/assemblies.blob`
* `assemblies/assemblies.[ARCHITECTURE].blob`
`assemblies.[ARCHITECTURE].blob` contains architecture-specific
assemblies, e.g. `System.Private.CoreLib.dll` built for x86 would be
placed within `assemblies.x86.blob`. `ARCHITECTURE` is one of `x86`,
`x86_64`, `armeabi_v7a`, or `arm64_v8a`; note use of `_` instead of
`-`, which is different from the `lib/ARCHITECTURE` convention within
`.apk` files. This is done because this is apparently what Android
and `bundletool` do, e.g. creating `split_config.armeabi_v7a.apk`.
Once the architecture-neutral `assemblies.blob` and appropriate
(singular!) `assemblies.[ARCHITECTURE].blob` for the current
architecture is found and `mmap()`'d, `.apk` entry traversal can end.
There is no longer a need to parse the entire `.apk` during startup.
The reduction in the number of `mmap()` system calls required can
have a noticeable impact on process startup, particularly with
.NET SDK for Android & MAUI; see below for timing details.
The assembly store format uses the followings structures:
struct AssemblyStoreHeader {
uint32_t magic, version;
uint32_t local_entry_count; // Number of AssemblyStoreAssemblyDescriptor entries
uint32_t global_entry_count; // Number of AssemblyStoreAssemblyDescriptor entries in entire app, across all *.blob files
uint32_t store_id;
};
struct AssemblyStoreAssemblyDescriptor {
uint32_t data_offset, data_size; // Offset from beginning of file for .dll data
uint32_t debug_data_offset, debug_data_size; // Offset from beginning of file for .pdb data
uint32_t config_data_offset, config_data_size; // Offset from beginning of file for .dll.config data
};
struct AssemblyStoreHashEntry {
union {
uint64_t hash64; // 64-bit xxhash of assembly filename
uint32_t hash64; // 32-bit xxhash of assembly filename
};
uint32_t mapping_index, local_store_index, store_id;
};
The assembly store format is roughly as follows:
AssemblyStoreHeader header {…};
AssemblyStoreAssemblyDescriptor assemblies [header.local_entry_count];
// The following two entries exist only when header.store_id == 0
AssemblyStoreHashEntry hashes32[header.global_entry_count];
AssemblyStoreHashEntry hashes64[header.global_entry_count];
uint8_t data[];
Note that `AssemblyStoreFileFormat::hashes32` and
`AssemblyStoreFileFormat::hashes64` are *sorted by their hash*.
Further note that assembly *filenames* are not present.
`EmbeddedAssemblies::blob_assemblies_open_from_bundles()` will hash
the filename, then binary search the appropriate `hashes*` array to
get the appropriate assembly information.
As the assembly store format doesn't include assembly names, `.apk`
and `.aab` files will also contain an `assemblies.manifest` file,
which contains the assembly names and other information in a human-
readable format; it is also used by `assembly-store-reader`:
Hash 32 Hash 64 Blob ID Blob idx Name
0xa2e0939b 0x4288cfb749e4c631 000 0000 Xamarin.AndroidX.Activity
…
0xad6f1e8a 0x6b0ff375198b9c17 001 0000 System.Private.CoreLib
Add a new `tools/assembly-store-reader` utility which can read the
new `assemblies*.blob` files:
% tools/scripts/read-assembly-store path/to/app.apk
Store set 'base_assemblies':
Is complete set? yes
Number of stores in the set: 5
Assemblies:
0:
Name: Xamarin.AndroidX.Activity
Store ID: 0 (shared)
Hashes: 32-bit == 0xa2e0939b; 64-bit == 0x4288cfb749e4c631
Assembly image: offset == 1084; size == 14493
Debug data: absent
Config file: absent
…
16:
Name: System.Private.CoreLib
Store ID: 1 (x86)
Hashes: 32-bit == 0xad6f1e8a; 64-bit == 0x6b0ff375198b9c17
Assembly image: offset == 44; size == 530029
Debug data: absent
Config file: absent
…
On a Pixel 3 XL (arm64-v8a) running Android 12 with MAUI
6.0.101-preview.10.1952, we observe:
~~ MAUI: Displayed Time ~~
| Before ms | After ms | Δ | Notes |
| ---------:| --------: | -----------: | ------------------------------------- |
| 1016.800 | 892.600 | -12.21% ✓ | defaults; profiled AOT; 32-bit build |
| 1016.100 | 894.700 | -11.95% ✓ | defaults; profiled AOT; 64-bit build |
| 1104.200 | 922.000 | -16.50% ✓ | defaults; full AOT+LLVM; 64-bit build |
| 1102.700 | 926.100 | -16.02% ✓ | defaults; full AOT; 32-bit build |
| 1108.400 | 932.600 | -15.86% ✓ | defaults; full AOT; 64-bit build |
| 1106.300 | 932.600 | -15.70% ✓ | defaults; full AOT+LLVM; 32-bit build |
| 1292.000 | 1271.800 | -1.56% ✓ | defaults; 64-bit build |
| 1307.000 | 1275.400 | -2.42% ✓ | defaults; 32-bit build |
Displayed time reduces by ~12% when Profiled AOT is used.
It is interesting to note that **Displayed time** is nearly identical
for the default (JIT) settings case. It's most probably caused by the
amount of JIT-ed code between `OnCreate()` and the time when the
application screen is presented, most likely the time is spent JIT-ing
MAUI rendering code.
~~ MAUI: Total native init time (before `OnCreate()`) ~~
| Before ms | After ms | Δ | Notes |
| --------: | --------: | -----------: | ------------------------------------- |
| 96.727 | 88.921 | -8.07% ✓ | defaults; 32-bit build |
| 97.236 | 89.693 | -7.76% ✓ | defaults; 64-bit build |
| 169.315 | 108.845 | -35.71% ✓ | defaults; profiled AOT; 32-bit build |
| 170.061 | 109.071 | -35.86% ✓ | defaults; profiled AOT; 64-bit build |
| 363.864 | 208.949 | -42.57% ✓ | defaults; full AOT; 64-bit build |
| 363.629 | 209.092 | -42.50% ✓ | defaults; full AOT; 32-bit build |
| 373.203 | 218.289 | -41.51% ✓ | defaults; full AOT+LLVM; 64-bit build |
| 372.783 | 219.003 | -41.25% ✓ | defaults; full AOT+LLVM; 32-bit build |
Note that "native init time" includes running `JNIEnv.Initialize()`,
which requires loading `Mono.Android.dll` + dependencies such as
`System.Private.CoreLib.dll`, which in turn means that the AOT DSOs
such as `libaot-System.Private.CoreLib.dll.so` must *also* be loaded.
The loading of the AOT DSOs is why JIT is fastest here (no AOT DSOs),
and why Profiled AOT is faster than Full AOT (smaller DSOs).
~~ Plain Xamarin.Android: Displayed Time ~~
| Before ms | After ms | Δ | Notes |
| --------: | --------: | -----------: | ------------------------------------- |
| 289.300 | 251.000 | -13.24% ✓ | defaults; full AOT+LLVM; 64-bit build |
| 286.300 | 252.900 | -11.67% ✓ | defaults; full AOT; 64-bit build |
| 285.700 | 255.300 | -10.64% ✓ | defaults; profiled AOT; 32-bit build |
| 282.900 | 255.800 | -9.58% ✓ | defaults; full AOT+LLVM; 32-bit build |
| 286.100 | 256.500 | -10.35% ✓ | defaults; full AOT; 32-bit build |
| 286.100 | 258.000 | -9.82% ✓ | defaults; profiled AOT; 64-bit build |
| 328.900 | 310.600 | -5.56% ✓ | defaults; 32-bit build |
| 319.300 | 313.000 | -1.97% ✓ | defaults; 64-bit build |
~~ Plain Xamarin.Android: Total native init time (before `OnCreate()`) ~~
| Before ms | After ms | Δ | Notes |
| --------: | --------: | -----------: | ------------------------------------- |
| 59.768 | 42.694 | -28.57% ✓ | defaults; profiled AOT; 64-bit build |
| 60.056 | 42.990 | -28.42% ✓ | defaults; profiled AOT; 32-bit build |
| 65.829 | 48.684 | -26.05% ✓ | defaults; full AOT; 64-bit build |
| 65.688 | 48.713 | -25.84% ✓ | defaults; full AOT; 32-bit build |
| 67.159 | 49.938 | -25.64% ✓ | defaults; full AOT+LLVM; 64-bit build |
| 67.514 | 50.465 | -25.25% ✓ | defaults; full AOT+LLVM; 32-bit build |
| 66.758 | 62.531 | -6.33% ✓ | defaults; 32-bit build |
| 67.252 | 62.829 | -6.58% ✓ | defaults; 64-bit build |
Fixes: https://github.com/xamarin/xamarin-android/issues/5295
Our Open Source build artifact docs were never updated to cover the
transition from Jenkins to Azure Pipelines. The `JenkinsBuildArtifacts`
file has been renamed to `OSSBuildArtifacts` and the content has been
updated to reflect the new way to obtain and install these artifacts.
Running under .NET 5+, the
`BuildTest.BuildBasicApplicationCheckConfigFiles()` test fails with:
UnnamedProject.dll.config was must be copied to Intermediate directory
Expected: True
But was: False
After review, it doesn't seem like Xamarin.Android needs to support
`.dll.config` files in .NET 5+ at all.
1. `<dllmap/>` is not supported. It was a feature of Mono.
[`NativeLibrary`][0] is the replacement, but only exists in
.NET Core 3.0+.
2. `appSettings` only work via a compat NuGet package:
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
However, this NuGet package does not work in the current
Xamarin.Android (it throws `PlatformNotSupportedException`), and
there is no other mechanism to support `appSettings`.
All MSBuild targets related to `.config` files have been moved to
`Xamarin.Android.Legacy.targets`.
If a .NET 5+ build encounters a `.dll.config` file, an XA1024 warning
will be generated:
warning XA1024: Ignoring configuration file 'Foo.dll.config'.
.NET configuration files are not supported in Xamarin.Android projects that target .NET 5 or higher.
This is unfortunately an un-actionable warning message, so we may want
to reconsider this approach.
TODO/Possible answer: if we ever have a mechanism to support NuGet
package creation a'la `dotnet pack`, we could emit the XA1024 warning
at package creation if the `.dll.config` is included in the NuGet.
I added updated tests around the`_CopyConfigFiles` MSBuild target to
run under `dotnet` context.
[0]: https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.nativelibrary
Context: https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1009374/
This is a first step toward localizing the MSBuild error and warning
messages produced by `Xamarin.Android.Build.Tasks.dll`.
We will be following the [.NET Resource Localization pattern][0] and
generating satellite assemblies using [`.resx` files][1], in particular
`src/Xamarin.Android.Build.Tasks/Properties/Resources.resx`.
`Resources.resx` is an XML file, and will contain `/root/data`
elements in which `//data/@name` will start with the Xamarin.Android
error or warning code, and `//data/value` will be the error or
warning message:
<root>
<data name="XA4214" xml:space="preserve">
<value>The managed type `{0}` exists in multiple assemblies: {1}. Please refactor the managed type names in these assemblies so that they are not identical.</value>
</data>
</root>
An optional `//data/comment` element may be provided to describe the
meaning within the `//data/value` element to translators:
<data name="XA4214" xml:space="preserve">
<value>The managed type `{0}` exists in multiple assemblies: {1}. Please refactor the managed type names in these assemblies so that they are not identical.</value>
<comment>
{0} - The managed type name
{1} - Comma-separated list of all the assemblies where the managed type exists
</comment>
</data>
During the build, `Resources.resx` will be translated into a
`Resources.Designer.cs` file:
namespace Xamarin.Android.Tasks.Properties {
internal partial class Resources {
internal static string XA4214 {
get => ...
}
}
}
The `Resources` members should be used to obtain all strings for use
in `LogCodedError()` and `LogCodedWarning()` calls:
Log.LogCodedWarning ("XA4214", Properties.Resources.XA4214, kvp.Key, string.Join (", ", kvp.Value));
When an MSBuild error or warning code is used with more than one
output string, then a semantically meaningful suffix should be used
to distinguish between the two:
<data name="XA4214_Result" xml:space="preserve">
<value>References to the type `{0}` will refer to `{0}, {1}`.</value>
</data>
Note that this infrastructure does not interoperate with C#6 string
interpolation. Any error or warning messages currently using C#6
string interpolation will need to use .NET 1.0-style format strings.
Our translation team doesn't work directly with `.resx` files.
Instead, the translation team works with [XLIFF files][2].
`Resources.resx` is converted into a set of
`src/Xamarin.Android.Build.Tasks/Properties/xlf/Resources.*.xlf`
files via `XliffTasks.targets` from the [dotnet/xliff-tasks][3] repo.
The `Resources.*.xlf` files should be automatically updated whenever
`Resources.resx` is updated.
Other:
* This approach leaves the error code `XA4214` as a string literal
for now. This differs from what dotnet/sdk and microsoft/msbuild
do; they instead include the message code as part of the string
resource in the `.resx` file. That might sometimes provide useful
additional context for the translation team, but it also requires
using a different set of logging methods from
`Microsoft.Build.Utilities.TaskLoggingHelper`.
* Fix the Test MSBuild Azure Pipelines build
Specify the `feedsToUse` and `nugetConfigPath` inputs for the
[`NuGetCommand@2`][6] Azure Pipelines task so that the NuGet
restore step will be able to restore XliffTasks successfully from
the dotnet-eng Azure DevOps NuGet package feed.
This resolves the following error:
The nuget command failed with exit code(1) and error(Errors in packages.config projects
Unable to find version '1.0.0-beta.19252.1' of package 'XliffTasks'.
C:\Users\dlab14\.nuget\packages\: Package 'XliffTasks.1.0.0-beta.19252.1' is not found on source 'C:\Users\dlab14\.nuget\packages\'.
https://api.nuget.org/v3/index.json: Package 'XliffTasks.1.0.0-beta.19252.1' is not found on source 'https://api.nuget.org/v3/index.json'.)
TODO:
* When `Xamarin.Android.Build.Tasks.csproj` is converted into a
[short-form project][4], add a dependency on dotnet/arcade and
switch to using the [`GenerateResxSource` mechanism][5] instead
of using `%(EmbeddedResource.Generator)`=ResXFileCodeGenerator
and set `$(UsingToolXliff)`=True. This would match dotnet/sdk.
[0]: https://docs.microsoft.com/dotnet/framework/resources/index
[1]: https://docs.microsoft.com/dotnet/framework/resources/creating-resource-files-for-desktop-apps#resources-in-resx-files
[2]: http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html
[3]: https://github.com/dotnet/xliff-tasks
[4]: https://docs.microsoft.com/visualstudio/msbuild/how-to-use-project-sdk
[5]: e67d9f0980/Documentation/ArcadeSdk.md (generateresxsource-bool)
[6]: https://docs.microsoft.com/azure/devops/pipelines/tasks/package/nuget
I recently found the Xamarin Profiler / GUI wasn't really suitable for
profiling Xamarin.Android startup on devices.
This is basically a brain dump of every way I have found to get
different timing information.
It should be useful in timing such things as Xamarin.Forms startup,
etc.
Context: https://gitter.im/xamarin/xamarin-android?at=5c4a25ba7a0f4d5b1900f7a4
Context: https://gitter.im/xamarin/xamarin-android?at=5c4a9d968ce4bb25b80795d3
The current documentation structure was found to be confusing, in
that a developer on Windows believed that they needed to install Mono
in order to build xamarin-android on Windows, which not only is not
the case, but *introduces* obscure build failures and confusion:
CoreCompile:
C:\Program Files\Mono\lib\mono\msbuild\15.0\bin\Roslyn\csc.exe ...
error MSB6006: "csc.exe" exited with code 1.
A possible fix could be to add a Windows section to the build
dependencies page, but we thought it would be clearer if we just
completely split apart the Linux/macOS ("Unix") instructions from the
Windows instructions, instead of attempting to share contents.
Move the build dependencies and build instructions for macOS and
Linux into `Documentation/building/unix`.
Move the build instructions and *add* a build dependencies page for
Windows into `Documentation/building/windows`.
Add a link to the [Using Your Build][0] page in the Windows build
instructions to make it easier for contributors to find the next step
about how to build a Xamarin.Android application after they have
built `Xamarin.Android.sln`.
Mention the (relatively new) `Xamarin.Android.Build.Tasks.sln` as a
way to work around output assembly file locking when working on the
`Xamarin.Android.Build.Tasks.csproj` project on Windows.
[0]: 578e781ba1/Documentation/workflow/UsingYourBuild.md
Fixes: https://github.com/xamarin/xamarin-android/issues/1423
Fixes: https://github.com/xamarin/xamarin-android/issues/2040
Bumps to r8/d8-1.2@125b72.
~~ Overview ~~
This enables `d8` and `r8` integration for Xamarin.Android.
`d8` is a "next-generation" dex compiler (over `dx`), and
`r8` is a replacement for ProGuard. For full details on the feature,
see `Documentation/guides/D8andR8.md`.
~~ MSBuild targets changes ~~
New MSBuild properties include:
- `$(AndroidDexTool)` - an enum-style property with options `dx`
and `d8`. Defaults to `dx`.
- `$(AndroidLinkTool)` - an enum-style property, that can be left
blank to disable code shrinking.
Valid values are `proguard` and `r8`.
Existing MSBuild properties still retain the old behavior:
- `$(AndroidEnableProguard)` will set `$(AndroidLinkTool)` to
`proguard`, although it is no longer used internally by
Xamarin.Android targets.
- `$(AndroidEnableDesugar)` will default to `true` if `d8` or `r8`
are used.
New MSBuild tasks include:
- `<D8/>`: runs `d8.jar` with the required options for
Xamarin.Android.
- `<R8/>`: subclasses `<D8/>`, and adds functionality for multi-dex
and code-shrinking.
Additionally, any new MSBuild targets are placed in a new
`Xamarin.Android.D8.targets` file. This is good first step to make
`Xamarin.Android.Common.targets` smaller.
Additionally:
* `build.props` is now invalidated via the `$(AndroidDexTool)`
and `$(AndroidLinkTool)` properties, instead of
`$(AndroidEnableProguard)`
* `build.props` is invalidated via `$(AndroidEnableDesugar)`
* Refactored `$(IntermediateOutputPath)_dex_stamp` stamp file in
`_CompileToDalvikWithDx` and `_CompileToDalvikWithD8` to match the
new convention of `$(_AndroidStampDirectory)_CompileToDalvik.stamp`
* `*.dex` files weren't in `@(FileWrites)`?!
* `<CompileToDalvik/>` had a `DexOutputs` output property that was
completely unused, so I removed it. Also removed extra log messages.
~~ Test changes ~~
Tests that need to validate various combinations of properties are
now using parameters such as:
[Values ("dx", "d8")] string dexTool, [Values ("", "proguard", "r8")] string linkTool
Set on the `XamarinAndroidApplicationProject` such as:
var proj = new XamarinAndroidApplicationProject {
DexTool = dexTool,
LinkTool = linkTool,
};
In other cases, a simple `useD8` flag was added to set `DexTool="d8"`.
Since adding test parameters, exponentially causes our test cases to
expand, I removed some non-essential parameters:
- `BuildProguardEnabledProject()` dropped `useLatestSdk`, as it does
not seem applicable here (and is deprecated). Otherwise would
have 24 test cases...
- `BuildApplicationWithSpacesInPath()` dropped `isRelease` and
defaulted it to `true`. We aren't going to likely encounter
issues with spaces in a path that happen *only* in a `Debug`
build. Otherwise we would have 24 test cases here...
- `Desugar()` dropped `enableDesugar` because it is certain this
application project will not build *without* desugar. We don't
need to test this, and would have 24 test cases otherwise...
Also dropped some `[TestCaseSource]` attributes where the `[Values]`
parameter was much cleaner.
~~ Changes to test/sample projects ~~
`HelloWorld` - `$(AndroidDexTool)` set to `d8` if unspecified,
so we can track the performance benefit.
`Xamarin.Forms Integration` - uses `d8` and `$(AndroidLinkTool)` set
to `r8`, using a `proguard.cfg` file for Xamarin.Forms. Will help us
track startup performance benefits of Java code shrinking and build
performance.
`Mono.Android-Tests` - uses `d8` and `$(AndroidLinkTool)` set to
`r8`, to verify these on-device tests pass.
`Runtime-MultiDex` - `$(AndroidDexTool)` set to `d8` if unspecified,
to validate multi-dex is working properly with `d8`.
~~ xamarin-android build changes ~~
The `<DownloadUri/>` MSBuild task now has an optional `HashHeader`
property. When set, an http HEAD request is made to the URL, and the
destination file path gets a suffix added for the value.
`DownloadUri.DestinationFiles` is changed to an `[Output]` property,
as the destination paths could change due to the `HashHeader`.
Chromium's `depot_tools` are downloaded the same as all of our other
dependencies. As the `depot_tools` distribution filename is
unversioned, we use the `x-goog-hash` header to derive a "version" so
that we don't needlessly download the file.
~~ Deployment changes ~~
Three new files will need to be included in Xamarin.Android
installers:
- `d8.jar`
- `r8.jar`
- `Xamarin.Android.D8.targets`
~~ General changes ~~
* Fixed doc for `xa4304` error code
* Added `xa4305` error code for `CompileToDalvik`, `R8`, and
`<CreateMultiDexMainDexClassList/>`
* Removed log messages in `<CreateMultiDexMainDexClassList/>`
~~ Performance Comparison ~~
| MSBuild Target | Options Enabled | Time | APK size (bytes) | dex size (bytes) |
| --- | --- | ---: | ---: | ---: |
| _CompileToDalvikWithDx | n/a | 11074ms | 13378157 | 3894720 |
| _CompileToDalvikWithD8 | d8, (desugar enabled) | 8543ms | 13124205 | 3314064 |
| _CompileToDalvikWithD8 | d8, (desugar disabled) | 9550ms | 13124205 | 3314064 |
| _CompileToDalvikWithDx | multi-dex | 15632ms | 13390498 | 3916496 |
| _CompileToDalvikWithD8 | d8, multi-dex | 25979ms | 13054626 | 3264096 |
| _CompileToDalvikWithDx | proguard | 11903ms | 12804717 | 2446964 |
| _CompileToDalvikWithD8 | d8, r8 | 13799ms | 12513901 | 1835588 |
| _CompileToDalvikWithDx | multi-dex, proguard | 17279ms | 12804770 | 2449512 |
| _CompileToDalvikWithD8 | d8, multi-dex, r8 | 13792ms | 12513954 | 1837588 |
*NOTE: desugar is enabled by default with d8/r8*
I timed this builds with [this script][powershell_script], with a
"Hello World" Xamarin.Forms app.
Build logs here: [d8andr8.zip][d8andr8_zip]
One can draw their own conclusions on which options are faster,
better, smaller. See further detail in `D8andR8.md`.
[powershell_script]: 39e2854f6c/build.ps1
[d8andr8_zip]: https://github.com/xamarin/xamarin-android/files/2470385/d8andr8.zip
Co-authored-by: Atsushi Eno <atsushieno@gmail.com>
Fixes: https://github.com/xamarin/xamarin-android/issues/2247
We currently have two targets that fail to build incrementally:
- `_ResolveLibraryProjectImports`
- `_GeneratePackageManagerJava`
Both of these targets declare `Outputs`, but don't always update the
timestamp of the output file. They used `CopyIfChanged` logic, so they
won't write to the file if nothing changed.
However...
We can't just add `<Touch/>` calls here either, as the `Outputs` of
these targets are `Inputs` to other *slow* targets (`_CompileJava`,
`_UpdateAndroidResgen`, and friends). If we used `<Touch/>` here,
things would be worse and trigger the *slow* targets to run.
So the only option here is to use a "stamp" file, this allows these
targets to properly build incrementally and not trigger other targets.
I updated a `IncrementalBuildTest` to include a test case checking all
three of these targets.
Future changes:
- I am going to need to audit many of our MSBuild targets for this
same problem, and so I will likely need to add many new stamp files.
- To simplify this, we should adopt a new convention of placing stamp
files in `$(IntermediateOutputPath)stamp\` or
`$(_AndroidStampDirectory)`.
- The stamp file should be named the same as the target where it is
used as an `Output`.
Documentation:
I also started some initial documentation on "MSBuild Best Practices",
which we can expand upon in future PRs. See the `Stamp Files` section
on what is relevant in this PR.
Context: https://github.com/xamarin/xamarin-android/pull/1343
> Trying to refactor `README.md` so it's more concise...based on the
> user's goal to contribute or provide feedback when visiting the
> repository.
If we're to make `README.md` shorter, then the contents of `README.md`
need to be moved *elsewhere*.
Reorganize the Documentation, taking inspiration from dotnet/coreclr
for general organization principals:
* Documentation/building: How do we build this thing?
* Documentation/guides: "Product documentation" which should live
"elsewhere", but we want here for sanity purposes.
In particular, the Build Process documentation.
* Documentation/project-docs: What is Xamarin.Android?
* Documentation/workflow: How do we develop this thing?