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

D8 and R8 Integration #2040

Closed
jonathanpeppers opened this issue Aug 6, 2018 · 9 comments
Closed

D8 and R8 Integration #2040

jonathanpeppers opened this issue Aug 6, 2018 · 9 comments
Labels
Area: App+Library Build Issues when building Library projects or Application projects. enhancement Proposed change to current functionality. proposal

Comments

@jonathanpeppers
Copy link
Member

jonathanpeppers commented Aug 6, 2018

This is the D8 and R8 integration specification for Xamarin.Android.

What is D8? What is R8?

At a high level, here are the steps that occur during an Android application's Java compilation:

  • javac compiles Java code
  • desugar remove's the "sugar" (from Java 8 features) that are not fully supported on Android
  • proguard shrinks compiled Java code
  • dx "dexes" compiled Java code into Android dex format. This is an alternate Java bytecode format supported by the Android platform.

This process has a few issues, such as:

  • proguard is made by a third party, and aimed for Java in general (not Android specific)
  • dx is slower than it could be

So in 2017, Google announced a "next-generation" dex compiler named D8.

  • D8 is a direct replacement for dx
  • R8 is a replacement for proguard, that also "dexes" at the same time. If using R8, a D8 call is not needed.

Both tools have support for various other Android-specifics:

  • Both desugar by default unless the --no-desugaring switch is specified
  • Both support multidex
    • R8 additionally has support to generate a default multidex.keep file, that proguard can generate

Additionally, R8 is geared to be backwards compatible to proguard. It uses the same file format for configuration and command-line parameters as proguard. However, at the time of writing this, there are still several flags/features not implemented in R8 yet.

For more information on how R8 compares to proguard, see a great article written by the proguard team here.

You can find the source for D8 and R8 here.

For reference, d8 --help:

Usage: d8 [options] <input-files>
 where <input-files> are any combination of dex, class, zip, jar, or apk files
 and options are:
  --debug                 # Compile with debugging information (default).
  --release               # Compile without debugging information.
  --output <file>         # Output result in <outfile>.
                          # <file> must be an existing directory or a zip file.
  --lib <file>            # Add <file> as a library resource.
  --classpath <file>      # Add <file> as a classpath resource.
  --min-api               # Minimum Android API level compatibility
  --intermediate          # Compile an intermediate result intended for later
                          # merging.
  --file-per-class        # Produce a separate dex file per input class
  --no-desugaring         # Force disable desugaring.
  --main-dex-list <file>  # List of classes to place in the primary dex file.
  --version               # Print the version of d8.
  --help                  # Print this message.

For reference, r8 --help:

Usage: r8 [options] <input-files>
 where <input-files> are any combination of dex, class, zip, jar, or apk files
 and options are:
  --release                # Compile without debugging information (default).
  --debug                  # Compile with debugging information.
  --output <file>          # Output result in <file>.
                           # <file> must be an existing directory or a zip file.
  --lib <file>             # Add <file> as a library resource.
  --min-api                # Minimum Android API level compatibility.
  --pg-conf <file>         # Proguard configuration <file>.
  --pg-map-output <file>   # Output the resulting name and line mapping to <file>.
  --no-tree-shaking        # Force disable tree shaking of unreachable classes.
  --no-minification        # Force disable minification of names.
  --no-desugaring          # Force disable desugaring.
  --main-dex-rules <file>  # Proguard keep rules for classes to place in the
                           # primary dex file.
  --main-dex-list <file>   # List of classes to place in the primary dex file.
  --main-dex-list-output <file>  # Output the full main-dex list in <file>.
  --version                # Print the version of r8.
  --help                   # Print this message.

What does Xamarin.Android do now?

In other words, what is currently happening before we introduce D8/R8 support?

  1. The Javac MSBuild task compiles *.java files to a classes.zip file.
  2. The Desugar MSBuild task "desugars" using desugar_deploy.jar if $(AndroidEnableDesugar) is True.
  3. The Proguard MSBuild task shrinks the compiled Java code if $(AndroidEnableProguard) is True. Developers may also supply custom proguard configuration files via ProguardConfiguration build items.
  4. The CreateMultiDexMainDexClassList MSBuild task runs proguard to generate a final, combined multidex.keep file if $(AndroidEnableMultiDex) is True. Developers can also supply custom multidex.keep files via MultiDexMainDexList build items.
  5. The CompileToDalvik MSBuild task runs dx.jar to generate a final classes.dex file in $(IntermediateOutputPath)android\bin. If multidex is enabled, a classes2.dex (and potentially more) are also generated in this location.

What would this process look like with D8 / R8?

Two new MSBuild tasks named R8 and D8 will be created.

  1. The Javac MSBuild task will remain unchanged.
  2. R8 will be invoked to create a multidex.keep file if $(AndroidEnableMultiDex) is True.
  3. D8 will run if $(AndroidEnableProguard) is False and "desugar" by default.
  4. Otherwise, R8 will run if $(AndroidEnableProguard) is True and will also "desugar" by default.

So in addition to be being faster (if Google's claims are true), we will be calling less tooling to accomplish the same results.

So how do developers use it? What are sensible MSBuild property defaults?

Currently, a csproj file might have the following properties:

<Project>
    <PropertyGroup>
        <AndroidEnableProguard>True</AndroidEnableProguard>
        <AndroidEnableMultiDex>True</AndroidEnableMultiDex>
        <AndroidEnableDesugar>True</AndroidEnableDesugar>
    </PropertyGroup>
</Project>

To enable the new behavior, we should introduce two new enum-style properties:

  • $(AndroidDexGenerator) - supports dx or d8
  • $(AndroidLinkTool) - supports proguard or r8

But for an existing project, a developer could opt-in to the new behavior with two properties:

<Project>
    <PropertyGroup>
        <AndroidEnableProguard>True</AndroidEnableProguard>
        <AndroidEnableMultiDex>True</AndroidEnableMultiDex>
        <AndroidEnableDesugar>True</AndroidEnableDesugar>
        <!--New properties-->
        <AndroidDexGenerator>d8</AndroidDexGenerator>
        <AndroidLinkTool>r8</AndroidLinkTool>
    </PropertyGroup>
</Project>

There should be two new MSBuild properties to configure here, because:

  • You could use D8 in combination with proguard, as R8 is not "feature complete" in comparison to proguard.
  • You may not want to use code shrinking at all, but still use D8 instead of dx.
  • You shouldn't be able to use dx in combination with R8, it doesn't make sense.
  • Developers should be able to use the existing properties for enabling code shrinking, multidex, and desugar.

Our reasonable defaults would be:

  • If AndroidDexGenerator is omitted, dx and CompileToDalvik should be used. Until D8/R8 integration is deemed stable and enabled by default.
  • If AndroidDexGenerator is d8 and AndroidEnableDesugar is omitted, AndroidEnableDesugar should be enabled.
  • If AndroidLinkTool is omitted and AndroidEnableProguard is true, we should default AndroidLinkTool to proguard.

MSBuild properties default to something like:

<AndroidDexGenerator Condition=" '$(AndroidDexGenerator)' == '' ">dx</AndroidDexGenerator>
<!--NOTE: $(AndroidLinkTool) would be blank if code shrinking is not used at all-->
<AndroidLinkTool Condition=" '$(AndroidLinkTool)' == '' And '$(AndroidEnableProguard)' == 'True' ">proguard</AndroidLinkTool>
<AndroidEnableDesugar Condition=" '$(AndroidEnableDesugar)' == '' And ('$(AndroidDexGenerator)' == 'd8' Or '$(AndroidLinkTool)' == 'r8') ">True</AndroidEnableDesugar>

If a user specifies combinations of properties:

  • AndroidDexGenerator = d8 and AndroidEnableProguard = True
    • AndroidLinkTool will get set to proguard
  • AndroidDexGenerator = dx and AndroidLinkTool = r8
    • This combination doesn't really make sense, but we don't need to do anything: only R8 will be called because it dexes and shrinks at the same time.
  • AndroidEnableDesugar is enabled when omitted, if either d8 or r8 are used

For new projects that want to use D8/R8, code shrinking, and multidex, it would make sense to specify:

<Project>
    <PropertyGroup>
        <AndroidEnableMultiDex>True</AndroidEnableMultiDex>
        <AndroidDexGenerator>d8</AndroidDexGenerator>
        <AndroidLinkTool>r8</AndroidLinkTool>
    </PropertyGroup>
</Project>

Additional D8 / R8 settings?

--debug or --release needs to be explicitly specified for both D8 and R8. We should use the AndroidIncludeDebugSymbols property for this.

$(D8ExtraArguments) and $(R8ExtraArguments) can be used to explicitly pass additional flags to D8 and R8.

How are we compiling / shipping D8 and R8?

We will add a submodule to xamarin-android for r8. It should be pinned to a commit with a reasonable release tag, such as 1.2.35 for now.

To build r8, we have to:

  • Download and unzip a tool named depot_tools from the Chromium project
  • Put the path to depot_tools in $PATH
  • Run gclient so it will download/bootstrap gradle, python, and other tools
  • Run python tools\gradle.py d8 r8 to compile d8.jar and r8.jar
  • We will need to ship d8.jar and r8.jar in our installers, similar to how we are shipping desugar_deploy.jar

Current Implementation

PR #2019 is the current implementation.

However, it became clear that a lot of the ideas around D8/R8 are not formalized or known.

The goal here will be to actually explain what everything should do, before I finish the implementation.

@jonathanpeppers jonathanpeppers added enhancement Proposed change to current functionality. Area: App+Library Build Issues when building Library projects or Application projects. labels Aug 6, 2018
@jonathanpeppers
Copy link
Member Author

jonathanpeppers commented Aug 6, 2018

TODO:
- [x] Rework to support using d8 + proguard
- [x] Link to this good article
- [x] Need to explain how r8 is backwards compatible to proguard

Spec has been updated above.

@JonDouglas
Copy link
Contributor

JonDouglas commented Aug 28, 2018

@jonathanpeppers

This proposal is very well done and covers the bases. I find it to be very straight-forward and sensible. 👍

One note on Desugar and Dx as I wasn't able to find an answer in the spec above:

The history of the flavors of desugar goes back to Android Studio 3.0 and 3.1+

For our current implementation of desugar, isn't the desugar.jar the external process version from Android Studio 3.0, and it has recently been integrated in the d8/r8 pipeline in Android Studio 3.1+? In other words, AndroidEnableDesugar will just be sending the --no-desugaring parameters to d8/r8. What about supporting the dx + desugar use-case? I have a feeling that the deprecation of the desugar.jar will happen around the same time as dx. So maybe that's not a use-case we consider in this proposal?

Similar to Desugar, Dx will also be phased out relatively soon, so it may be possible that future versions of Android tools will rely directly on d8 or r8 for dexing.

Just a generic question, what is the sensible default from a project perspective? From what I understand, r8 is the best performant tool to accomplish desugaring, minification, and dexing (Reuses items so it's much faster). Otherwise the user would use d8 if they choose not to desugar or use minification?

@jonathanpeppers
Copy link
Member Author

r8 is the same as d8 except it adds minification/shrinking (similar to proguard).

Both of them desugar by default and you can pass --no-desugaring to turn that off. AndroidEnableDesugar=False would pass this --no-desugaring flag, and AndroidEnableDesugar=True would not pass a flag.

dx + desugar wouldn't change any, it would work as it does currently.

In the future, projects could default to:

<Project>
    <PropertyGroup>
        <AndroidDexGenerator>d8</AndroidDexGenerator>
    </PropertyGroup>
</Project>

This would use d8 and desugar by default. If dx were completely removed at some time in the future, we could even leave the $(AndroidDexGenerator) property out.

I'm not sure if using r8 by default is a good idea, but worth considering if Android Studio does it. This would be similar to what would happen if we had proguard enabled by default.

@JonDouglas
Copy link
Contributor

Thanks for the clarification. I was thinking along the same lines. I believe the current default is d8 and opt-ing into r8 via flag. (enableR8)

@gmoney494
Copy link

does d8 have issues with enabling multi-dex?
I have this build error: Error MSB6006: "java" exited with code 1. (MSB6006) (attached are build logs: BuildLogs.txt)

If i mess with the settings with Desugaring in the csproj i get errors like here and here.

This doc and the links i shared are the closest i get to this bug.

@JonDouglas
Copy link
Contributor

@gmoney494 That initial support is a bit old using a 0.2.1 version of d8. In comparison, the latest version is 1.3.20. I would recommend waiting for our official support of d8/r8 as outlined in this issue. This will ensure the proper tool chain is used for desugaring and multidex.

@gmoney494
Copy link

@JonDouglas where can i find the latest nuget packages for those? I only went up to 0.2.1 because of what was available, last published by @atsushieno . And how long until this becomes the official support? I cant wait too long to get past this issue.

jonathanpeppers pushed a commit that referenced this issue Sep 21, 2018
Fixes: #2143
Context: #1639

Xamarin.Android's current implementation of desugar runs a command
such as:

    java -jar desugar_deploy.jar 
        --bootclasspath_entry ~\android-toolchain\sdk\platforms\android-28\android.jar 
        --min_sdk_version 11 
        --classpath_entry xamarin-android\bin\Debug\lib\xamarin.android\xbuild-frameworks\MonoAndroid\v9.0\mono.android.jar 
        --input Lambda.jar 
        --output obj\Debug\android\bin\desugared\14-57-25-90-94-EE-16-09-B8-68-88-BC-9D-FC-6C-89Lambda.jar

However, certain jars are failing with messages such as:

    Exception in thread "main" java.lang.TypeNotPresentException: Type okhttp3.Interceptor not present

Or another example:

    Error: java.lang.TypeNotPresentException : Type io.reactivex.functions.Action not present

The first fix here is to add the `--classpath_entry` flag for every
`--input`, for some reason `Desugar` is not treating `--input` jars as
classpath entries?

Next, we expanded on the `BuildTest.Desugar` test using a complicated
set of Java libraries from Maven central:

    proj.OtherBuildItems.Add (new BuildItem ("AndroidJavaLibrary", "okio-1.13.0.jar") {
        WebContent = "http://central.maven.org/maven2/com/squareup/okio/okio/1.13.0/okio-1.13.0.jar"
    });
    proj.OtherBuildItems.Add (new BuildItem ("AndroidJavaLibrary", "okhttp-3.8.0.jar") {
        WebContent = "http://central.maven.org/maven2/com/squareup/okhttp3/okhttp/3.8.0/okhttp-3.8.0.jar"
    });
    proj.OtherBuildItems.Add (new BuildItem ("AndroidJavaLibrary", "retrofit-2.3.0.jar") {
        WebContent = "http://central.maven.org/maven2/com/squareup/retrofit2/retrofit/2.3.0/retrofit-2.3.0.jar"
    });
    proj.OtherBuildItems.Add (new BuildItem ("AndroidJavaLibrary", "converter-gson-2.3.0.jar") {
        WebContent = "http://central.maven.org/maven2/com/squareup/retrofit2/converter-gson/2.3.0/converter-gson-2.3.0.jar"
    });
    proj.OtherBuildItems.Add (new BuildItem ("AndroidJavaLibrary", "gson-2.7.jar") {
        WebContent = "http://central.maven.org/maven2/com/google/code/gson/gson/2.7/gson-2.7.jar"
    });
    proj.OtherBuildItems.Add (new BuildItem ("AndroidAarLibrary", "twitter-core-3.3.0.aar") {
        WebContent = "http://repo.spring.io/libs-release/com/twitter/sdk/android/twitter-core/3.3.0/twitter-core-3.3.0.aar",
    });

This was working, as long as you had `android:minSdkVersion="24"` in
your `AndroidManifest.xml`. This wasn't ideal if you wanted to run
your app on older API levels...

Luckily, another command line switched solved this problem:

    //Added to the Desugar MSBuild task
    if (minApiVersion < 24) {
        cmd.AppendSwitch("--desugar_try_with_resources_omit_runtime_classes ");
    }

What a crazy name for a flag! Documented by `desugar` as:

    --[no]desugar_try_with_resources_omit_runtime_classes (a boolean; default: "false")
        Omits the runtime classes necessary to support try-with-resources from the
        output. This property has effect only if --
        desugar_try_with_resources_if_needed is used.
    --min_sdk_version (an integer; default: "1")
        Minimum targeted sdk version.  If >= 24, enables default methods in
        interfaces.

This makes sense that something would happen at API level 24...

Once doing this, the `Desugar` test passes without modifying
`minSdkVersion`.

The expanded `Desugar` test will also greatly help with our D8/R8
implementation
(#2040).

This complex set of Java dependencies from Maven will be useful.
jonathanpeppers pushed a commit to jonathanpeppers/xamarin-android that referenced this issue Sep 26, 2018
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Sep 26, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

[WIP]

Changes in Sprint 141:

* Using r8 version 1.2.48: https://r8.googlesource.com/r8/+/1.2.48
* Split the `R8` MSBuild task into `D8` and `R8` tasks.
* Fixed `Configuration` property, should be
  `Debug="$(AndroidIncludeDebugSymbols)"`
* Renamed `R8JarPath` and `R8ExtraArguments`
* Added `D8andR8.md` specification / Documentation
* Updated MSBuild property naming as per spec
* Added `--no-daemon` for gradle calls, to fix file-locking on Windows

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Sep 27, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

[WIP]

Changes in Sprint 142:

* Using r8 version 1.2.48: https://r8.googlesource.com/r8/+/1.2.48
* Split the `R8` MSBuild task into `D8` and `R8` tasks.
* Fixed `Configuration` property, should be
  `Debug="$(AndroidIncludeDebugSymbols)"`
* Renamed `R8JarPath` and `R8ExtraArguments`
* Added `D8andR8.md` specification / Documentation
* Updated MSBuild property naming as per spec
* Added `--no-daemon` for gradle calls, to fix file-locking on Windows
* Support `JavaOptions` and `JavaMaximumHeapSize`
* Call `<D8 />` separate from `<R8 />`
* Support `<Proguard />` + `<D8 />`
* Fixed broken multi-dex test
* Generating multidex.keep file with r8 now, when d8 is used

TODO:
* `MultiDexCustomMainDexFileList(true)` test is failing with `Illegal
  main-dex-list entry 'MyTest'.`
* Response file support with D8/R8
* General MSBuild targets cleanup. I want to move some subset of stuff
  to a new file.

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Sep 27, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

[WIP]

Changes in Sprint 142:

* Using r8 version 1.2.48: https://r8.googlesource.com/r8/+/1.2.48
* Split the `R8` MSBuild task into `D8` and `R8` tasks.
* Fixed `Configuration` property, should be
  `Debug="$(AndroidIncludeDebugSymbols)"`
* Renamed `R8JarPath` and `R8ExtraArguments`
* Added `D8andR8.md` specification / Documentation
* Updated MSBuild property naming as per spec
* Added `--no-daemon` for gradle calls, to fix file-locking on Windows
* Support `JavaOptions` and `JavaMaximumHeapSize`
* Call `<D8 />` separate from `<R8 />`
* Support `<Proguard />` + `<D8 />`
* Fixed broken multi-dex test
* Generating multidex.keep file with r8 now, when d8 is used
* Expanded upon `MultiDexCustomMainDexFileList` to use d8

TODO:
* Response file support with D8/R8
* General MSBuild targets cleanup. I want to move some subset of stuff
  to a new file.

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Sep 27, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

[WIP]

Changes in Sprint 142:

* Using r8 version 1.2.48: https://r8.googlesource.com/r8/+/1.2.48
* Split the `R8` MSBuild task into `D8` and `R8` tasks.
* Fixed `Configuration` property, should be
  `Debug="$(AndroidIncludeDebugSymbols)"`
* Renamed `R8JarPath` and `R8ExtraArguments`
* Added `D8andR8.md` specification / Documentation
* Updated MSBuild property naming as per spec
* Added `--no-daemon` for gradle calls, to fix file-locking on Windows
* Support `JavaOptions` and `JavaMaximumHeapSize`
* Call `<D8 />` separate from `<R8 />`
* Support `<Proguard />` + `<D8 />`
* Fixed broken multi-dex test
* Generating multidex.keep file with r8 now, when d8 is used
* Expanded upon `MultiDexCustomMainDexFileList` to use d8

TODO:
* General MSBuild targets cleanup. I want to move some subset of stuff
  to a new file.

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Sep 28, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

[WIP]

Changes in Sprint 142:

* Using r8 version 1.2.48: https://r8.googlesource.com/r8/+/1.2.48
* Split the `R8` MSBuild task into `D8` and `R8` tasks.
* Fixed `Configuration` property, should be
  `Debug="$(AndroidIncludeDebugSymbols)"`
* Renamed `R8JarPath` and `R8ExtraArguments`
* Added `D8andR8.md` specification / Documentation
* Updated MSBuild property naming as per spec
* Added `--no-daemon` for gradle calls, to fix file-locking on Windows
* Support `JavaOptions` and `JavaMaximumHeapSize`
* Call `<D8 />` separate from `<R8 />`
* Support `<Proguard />` + `<D8 />`
* Fixed broken multi-dex test
* Generating multidex.keep file with r8 now, when d8 is used
* Expanded upon `MultiDexCustomMainDexFileList` to use d8
* Put all d8/r8 related MSBuild targets in a new
  `Xamarin.Android.D8.targets` file

TODO:
* TEST!
* Profile dx / proguard vs d8 / r8
* Write a real commit message, drop all WIP/do-not-merge labels

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Oct 9, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

[WIP]

Changes in Sprint 142:

* Using r8 version 1.2.48: https://r8.googlesource.com/r8/+/1.2.48
* Split the `R8` MSBuild task into `D8` and `R8` tasks.
* Fixed `Configuration` property, should be
  `Debug="$(AndroidIncludeDebugSymbols)"`
* Renamed `R8JarPath` and `R8ExtraArguments`
* Added `D8andR8.md` specification / Documentation
* Updated MSBuild property naming as per spec
* Added `--no-daemon` for gradle calls, to fix file-locking on Windows
* Support `JavaOptions` and `JavaMaximumHeapSize`
* Call `<D8 />` separate from `<R8 />`
* Support `<Proguard />` + `<D8 />`
* Fixed broken multi-dex test
* Generating multidex.keep file with r8 now, when d8 is used
* Expanded upon `MultiDexCustomMainDexFileList` to use d8
* Put all d8/r8 related MSBuild targets in a new
  `Xamarin.Android.D8.targets` file

TODO:
* TEST!
* Profile dx / proguard vs d8 / r8
* Write a real commit message, drop all WIP/do-not-merge labels

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Oct 9, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

~~ 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:

- `$(AndroidDexGenerator)` - 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 `$(AndroidDexGenerator)`
  and `$(AndroidLinkTool)` properties, instead of
  `$(AndroidEnableProguard)`
* `build.props` is invalidated via `$(AndroidEnableDesugar)`

~~ Test changes ~~

Tests that need to validate various combinations of properties are now
using parameters such as:

    [Values ("dx", "d8")] string dexGenerator, [Values ("", "proguard", "r8")] string linkTool

Set on the `XamarinAndroidApplicationProject` such as:

    var proj = new XamarinAndroidApplicationProject {
        DexGenerator = dexGenerator,
        LinkTool = linkTool,
    };

In other cases, a simple `useD8` flag was added to set
`DexGenerator="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` - `$(AndroidDexGenerator)` 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` - `$(AndroidDexGenerator)` set to `d8` if
unspecified, to validate multi-dex is working properly with `d8`.

~~ Xamarin.Android build changes ~~

This adds https://r8.googlesource.com/r8 as a submodule in
`external/r8`, and builds `d8.jar` and `r8.jar` via `src/r8/r8.csproj`.

Currently using version 1.2.48 of r8.

~~ 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`

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Oct 11, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

~~ 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:

- `$(AndroidDexGenerator)` - 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 `$(AndroidDexGenerator)`
  and `$(AndroidLinkTool)` properties, instead of
  `$(AndroidEnableProguard)`
* `build.props` is invalidated via `$(AndroidEnableDesugar)`

~~ Test changes ~~

Tests that need to validate various combinations of properties are now
using parameters such as:

    [Values ("dx", "d8")] string dexGenerator, [Values ("", "proguard", "r8")] string linkTool

Set on the `XamarinAndroidApplicationProject` such as:

    var proj = new XamarinAndroidApplicationProject {
        DexGenerator = dexGenerator,
        LinkTool = linkTool,
    };

In other cases, a simple `useD8` flag was added to set
`DexGenerator="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` - `$(AndroidDexGenerator)` 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` - `$(AndroidDexGenerator)` set to `d8` if
unspecified, to validate multi-dex is working properly with `d8`.

~~ Xamarin.Android build changes ~~

This adds https://r8.googlesource.com/r8 as a submodule in
`external/r8`, and builds `d8.jar` and `r8.jar` via `src/r8/r8.csproj`.

Currently using version 1.2.48 of r8.

~~ 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]: https://github.com/jonathanpeppers/HelloWorld/blob/39e2854f6ca39c0941fb8bd6f2a16d8b7663003e/build.ps1
[d8andr8_zip]: https://github.com/xamarin/xamarin-android/files/2470385/d8andr8.zip

Co-authored-by: Atsushi Eno <[email protected]>
@ddobrev
Copy link

ddobrev commented Oct 12, 2018

Please fix because we cannot use the latest ExoPlayer.

jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Oct 19, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

~~ 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)`

~~ 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 ~~

This adds https://r8.googlesource.com/r8 as a submodule in
`external/r8`, and builds `d8.jar` and `r8.jar` via `src/r8/r8.csproj`.

Currently using version 1.2.50 of r8.

~~ 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]: https://github.com/jonathanpeppers/HelloWorld/blob/39e2854f6ca39c0941fb8bd6f2a16d8b7663003e/build.ps1
[d8andr8_zip]: https://github.com/xamarin/xamarin-android/files/2470385/d8andr8.zip

Co-authored-by: Atsushi Eno <[email protected]>
@martijn00
Copy link

Any idea when this is going to land? These changes are needed in combination with dotnet/java-interop#341 and dotnet/java-interop#25

jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Oct 22, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

~~ 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)`

~~ 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 ~~

This adds https://r8.googlesource.com/r8 as a submodule in
`external/r8`, and builds `d8.jar` and `r8.jar` via `src/r8/r8.csproj`.

Currently using version 1.2.50 of r8.

~~ 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]: https://github.com/jonathanpeppers/HelloWorld/blob/39e2854f6ca39c0941fb8bd6f2a16d8b7663003e/build.ps1
[d8andr8_zip]: https://github.com/xamarin/xamarin-android/files/2470385/d8andr8.zip

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Oct 23, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

~~ 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)`

~~ 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 ~~

This adds https://r8.googlesource.com/r8 as a submodule in
`external/r8`, and builds `d8.jar` and `r8.jar` via `src/r8/r8.csproj`.

Currently using version 1.2.50 of r8.

~~ 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]: https://github.com/jonathanpeppers/HelloWorld/blob/39e2854f6ca39c0941fb8bd6f2a16d8b7663003e/build.ps1
[d8andr8_zip]: https://github.com/xamarin/xamarin-android/files/2470385/d8andr8.zip

Co-authored-by: Atsushi Eno <[email protected]>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Oct 29, 2018
Fixes: dotnet#1423
Fixes: dotnet#2040

~~ 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)`

~~ 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 ~~

This adds https://r8.googlesource.com/r8 as a submodule in
`external/r8`, and builds `d8.jar` and `r8.jar` via `src/r8/r8.csproj`.

Currently using version 1.2.50 of r8.

~~ 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]: https://github.com/jonathanpeppers/HelloWorld/blob/39e2854f6ca39c0941fb8bd6f2a16d8b7663003e/build.ps1
[d8andr8_zip]: https://github.com/xamarin/xamarin-android/files/2470385/d8andr8.zip

Co-authored-by: Atsushi Eno <[email protected]>
jonpryor pushed a commit that referenced this issue Oct 30, 2018
Fixes: #1423
Fixes: #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]: https://github.com/jonathanpeppers/HelloWorld/blob/39e2854f6ca39c0941fb8bd6f2a16d8b7663003e/build.ps1
[d8andr8_zip]: https://github.com/xamarin/xamarin-android/files/2470385/d8andr8.zip

Co-authored-by: Atsushi Eno <[email protected]>
@ghost ghost locked as resolved and limited conversation to collaborators Jun 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Area: App+Library Build Issues when building Library projects or Application projects. enhancement Proposed change to current functionality. proposal
Projects
None yet
Development

No branches or pull requests

5 participants