Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] d8 and r8 support
Browse files Browse the repository at this point in the history
Fixes: dotnet#1423
Fixes: dotnet#2040

WIP

* Using r8 version 1.2.48: https://r8.googlesource.com/r8/+/1.2.48
  • Loading branch information
atsushieno authored and jonathanpeppers committed Sep 26, 2018
1 parent e390702 commit 151db1a
Show file tree
Hide file tree
Showing 22 changed files with 523 additions and 36 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
path = external/xamarin-android-tools
url = https://github.com/xamarin/xamarin-android-tools
branch = master
[submodule "external/r8"]
path = external/r8
url = https://r8.googlesource.com/r8
[submodule "external/dlfcn-win32"]
path = external/dlfcn-win32
url = https://github.com/dlfcn-win32/dlfcn-win32.git
Expand Down
13 changes: 13 additions & 0 deletions Documentation/guides/BuildProcess.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ when packaing Release applications.

This property is `False` by default.

- **AndroidEnableDesugar** – A boolean property that
determines if `desugar` is enabled. Android does not currently
support all Java 8 features, and the default toolchain implements
the new language features by performing bytecode transformations,
called `desugar`, on the output of the `javac` compiler.

- **AndroidEnableD8** – A boolean property that determines
whether or not use Google's new dexer (dx.jar alternative).
- **AndroidEnableMultiDex** – A boolean property that
determines whether or not multi-dex support will be used in the
final `.apk`.
Expand Down Expand Up @@ -419,6 +428,10 @@ when packaing Release applications.
This property should be `True` for Debug builds, and `False` for
Release projects.
- **AndroidUseR8** – A boolean property that determines
whether or not use Google's new Java code shrinker (proguard
alternative).

- **AotAssemblies** – A boolean property that determines
whether or not assemblies will be Ahead-of-Time compiled into
native code and included in the `.apk`.
Expand Down
2 changes: 1 addition & 1 deletion Documentation/guides/messages/xa4304.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Compiler Error XA4304
# Compiler Warning XA4304

The `Proguard` MSBuild task encountered a proguard configuration file
that was not found on disk. These files are generally declared in your
Expand Down
21 changes: 21 additions & 0 deletions Documentation/guides/messages/xa4305.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Compiler Error/Warning XA4305

The `CreateMultiDexMainDexClassList`, `CompileToDalvik` or `R8`
MSBuild task encountered a `multidex.keep` file that was not found on
disk. You can customize `multidex` settings for your Xamarin.Android
application by adding files with the `MultiDexMainDexList` build item,
which are combined into a final `multidex.keep` file.

To learn more about `multidex` and how it relates to Android
development, see the [Android documentation][android].

## Resolution

Verify you are not declaring a `MultiDexMainDexList` build item that
does not exist.

Consider submitting a [bug][bug] if you are getting this error/warning
under normal circumstances.

[android]: https://developer.android.com/studio/build/multidex
[bug]: https://github.com/xamarin/xamarin-android/wiki/Submitting-Bugs,-Feature-Requests,-and-Pull-Requests
9 changes: 7 additions & 2 deletions Xamarin.Android.sln
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools.Andro
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools.AndroidSdk-Tests", "external\xamarin-android-tools\src\Xamarin.Android.Tools.AndroidSdk\Tests\Xamarin.Android.Tools.AndroidSdk-Tests.csproj", "{1E5501E8-49C1-4659-838D-CC9720C5208F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "r8", "src\r8\r8.csproj", "{1BAFA0CC-0377-46CE-AB7B-7BB2E7B62F63}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proprietary", "build-tools\proprietary\proprietary.csproj", "{D93CAC27-3893-42A3-99F1-2BCA72E186F4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "download-bundle", "build-tools\download-bundle\download-bundle.csproj", "{1DA0CB12-5508-4E83-A242-0C8D6D99A49B}"
Expand Down Expand Up @@ -358,6 +360,10 @@ Global
{1DA0CB12-5508-4E83-A242-0C8D6D99A49B}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{1DA0CB12-5508-4E83-A242-0C8D6D99A49B}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{1DA0CB12-5508-4E83-A242-0C8D6D99A49B}.Release|AnyCPU.Build.0 = Release|Any CPU
{1BAFA0CC-0377-46CE-AB7B-7BB2E7B62F63}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
{1BAFA0CC-0377-46CE-AB7B-7BB2E7B62F63}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{1BAFA0CC-0377-46CE-AB7B-7BB2E7B62F63}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{1BAFA0CC-0377-46CE-AB7B-7BB2E7B62F63}.Release|AnyCPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -418,8 +424,7 @@ Global
{B8105878-D423-4159-A3E7-028298281EC6} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{1E5501E8-49C1-4659-838D-CC9720C5208F} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
{D93CAC27-3893-42A3-99F1-2BCA72E186F4} = {E351F97D-EA4F-4E7F-AAA0-8EBB1F2A4A62}
{1DA0CB12-5508-4E83-A242-0C8D6D99A49B} = {E351F97D-EA4F-4E7F-AAA0-8EBB1F2A4A62}
{1BAFA0CC-0377-46CE-AB7B-7BB2E7B62F63} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6}
Expand Down
1 change: 1 addition & 0 deletions external/r8
Submodule r8 added at 671655
9 changes: 9 additions & 0 deletions external/r8.tpnitems
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition=" '$(TpnIncludeExternalDependencies)' == 'True' ">
<ThirdPartyNotice Include="google/r8">
<LicenseFile>$(MSBuildThisFileDirectory)\r8\LICENSE</LicenseFile>
<SourceUrl>https://r8.googlesource.com/r8/</SourceUrl>
</ThirdPartyNotice>
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions src/Mono.Android/Test/Mono.Android-Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
<AndroidUseR8 Condition="'$(AndroidUseR8)' == ''">True</AndroidUseR8>
<AndroidEnableD8 Condition="'$(AndroidEnableD8)' == ''">True</AndroidEnableD8>
</PropertyGroup>
<Import Project="Mono.Android-Test.Shared.projitems" Label="Shared" Condition="Exists('Mono.Android-Test.Shared.projitems')" />
<Import Project="..\..\..\Configuration.props" />
Expand Down
10 changes: 8 additions & 2 deletions src/Xamarin.Android.Build.Tasks/Tasks/CompileToDalvik.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,14 @@ protected override string GenerateCommandLineCommands ()
cmd.AppendSwitchIfNotNull ("--input-list=", inputListFile);

if (MultiDexEnabled) {
cmd.AppendSwitch ("--multi-dex");
cmd.AppendSwitchIfNotNull ("--main-dex-list=", MultiDexMainDexListFile);
if (string.IsNullOrEmpty (MultiDexMainDexListFile)) {
Log.LogCodedWarning ("XA4305", $"MultiDex is enabled, but '{nameof (MultiDexMainDexListFile)}' was not specified.");
} else if (!File.Exists (MultiDexMainDexListFile)) {
Log.LogCodedWarning ("XA4305", MultiDexMainDexListFile, 0, $"MultiDex is enabled, but main dex list file '{MultiDexMainDexListFile}' does not exist.");
} else {
cmd.AppendSwitch ("--multi-dex");
cmd.AppendSwitchIfNotNull ("--main-dex-list=", MultiDexMainDexListFile);
}
}
cmd.AppendSwitchIfNotNull ("--output ", Path.GetDirectoryName (ClassesOutputDirectory));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,17 @@ public override bool Execute ()

var result = base.Execute () && !Log.HasLoggedErrors;

if (result && CustomMainDexListFiles != null && CustomMainDexListFiles.Any (x => File.Exists (x.ItemSpec))) {
foreach (var content in CustomMainDexListFiles.Select (i => File.ReadAllLines (i.ItemSpec)))
File.AppendAllLines (MultiDexMainDexListFile, content);
if (result && CustomMainDexListFiles?.Length > 0) {
var content = new List<string> ();
foreach (var file in CustomMainDexListFiles) {
if (File.Exists (file.ItemSpec)) {
content.Add (File.ReadAllText (file.ItemSpec));
} else {
Log.LogCodedError ("XA4305", file.ItemSpec, 0, $"'MultiDexMainDexList' file '{file.ItemSpec}' does not exist.");
}
}
File.WriteAllText (MultiDexMainDexListFile, string.Concat (content));
return true;
}

return result;
Expand Down
32 changes: 13 additions & 19 deletions src/Xamarin.Android.Build.Tasks/Tasks/Proguard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,17 @@ public class Proguard : ToolTask
[Required]
public string ProguardJarOutput { get; set; }

[Required]
public string ProguardGeneratedReferenceConfiguration { get; set; }

[Required]
public string ProguardGeneratedApplicationConfiguration { get; set; }

[Required]
public string ProguardCommonXamarinConfiguration { get; set; }

[Required]
public string ProguardConfigurationFiles { get; set; }

public ITaskItem[] JavaLibrariesToEmbed { get; set; }

public ITaskItem[] ExternalJavaLibraries { get; set; }
public ITaskItem[] JavaLibrariesToReference { get; set; }

public ITaskItem[] DoNotPackageJavaLibraries { get; set; }

public bool UseProguard { get; set; }

public string JavaOptions { get; set; }
Expand Down Expand Up @@ -119,15 +113,9 @@ protected override string GenerateCommandLineCommands ()
// skip invalid lines
}

var injars = new List<string> ();
var libjars = new List<string> ();
injars.Add (classesZip);
if (JavaLibrariesToEmbed != null)
foreach (var jarfile in JavaLibrariesToEmbed)
injars.Add (jarfile.ItemSpec);

using (var xamcfg = File.Create (ProguardCommonXamarinConfiguration))
GetType ().Assembly.GetManifestResourceStream ("proguard_xamarin.cfg").CopyTo (xamcfg);
if (!string.IsNullOrWhiteSpace (ProguardCommonXamarinConfiguration))
using (var xamcfg = File.Create (ProguardCommonXamarinConfiguration))
GetType ().Assembly.GetManifestResourceStream ("proguard_xamarin.cfg").CopyTo (xamcfg);

var configs = ProguardConfigurationFiles
.Replace ("{sdk.dir}", AndroidSdkDirectory + Path.DirectorySeparatorChar)
Expand All @@ -148,9 +136,15 @@ protected override string GenerateCommandLineCommands ()
Log.LogCodedWarning ("XA4304", file, 0, "Proguard configuration file '{0}' was not found.", file);
}

var injars = new List<string> ();
var libjars = new List<string> ();
injars.Add (classesZip);
if (JavaLibrariesToEmbed != null)
foreach (var jarfile in JavaLibrariesToEmbed)
injars.Add (jarfile.ItemSpec);
libjars.Add (JavaPlatformJarPath);
if (ExternalJavaLibraries != null)
foreach (var jarfile in ExternalJavaLibraries.Select (p => p.ItemSpec))
if (JavaLibrariesToReference != null)
foreach (var jarfile in JavaLibrariesToReference.Select (p => p.ItemSpec))
libjars.Add (jarfile);

cmd.AppendSwitchUnquotedIfNotNull ("-injars ", "\"'" + string.Join ($"'{ProguardInputJarFilter}{Path.PathSeparator}'", injars.Distinct ()) + $"'{ProguardInputJarFilter}\"");
Expand Down
147 changes: 147 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/R8.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright (C) 2018 Xamarin, Inc. All rights reserved.

using System;
using System.Linq;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Collections.Generic;
using Xamarin.Android.Tools;

namespace Xamarin.Android.Tasks
{

public class R8 : JavaToolTask
{
[Required]
public string R8JarPath { get; set; }

[Required]
public string OutputDirectory { get; set; }

public string Configuration { get; set; }

// It is loaded to calculate --min-api, which is used by desugaring part to determine which levels of desugaring it performs.
[Required]
public string AndroidManifestFile { get; set; }

// general r8 feature options.
public bool EnableDesugar { get; set; }
public bool EnableMinify { get; set; } // The Task has the option, but it is not supported at all.
public bool EnableTreeShaking { get; set; }

// Java libraries to embed or reference
[Required]
public string ClassesZip { get; set; }
[Required]
public string JavaPlatformJarPath { get; set; }
public ITaskItem [] JavaLibrariesToEmbed { get; set; }
public ITaskItem [] JavaLibrariesToReference { get; set; }

// used for proguard configuration settings
[Required]
public string AndroidSdkDirectory { get; set; }
[Required]
public string AcwMapFile { get; set; }
public string ProguardGeneratedReferenceConfiguration { get; set; }
public string ProguardGeneratedApplicationConfiguration { get; set; }
public string ProguardCommonXamarinConfiguration { get; set; }
[Required]
public string ProguardConfigurationFiles { get; set; }
public string ProguardMappingOutput { get; set; }

// multidex
public bool EnableMultiDex { get; set; }
public string MultiDexMainDexListFile { get; set; }

public string R8ExtraArguments { get; set; }

protected override string GenerateCommandLineCommands ()
{
var cmd = new CommandLineBuilder ();

cmd.AppendSwitchIfNotNull ("-jar ", R8JarPath);

if (!string.IsNullOrEmpty (R8ExtraArguments))
cmd.AppendSwitch (R8ExtraArguments); // it should contain "--dex".
if (Configuration.Equals ("Debug", StringComparison.OrdinalIgnoreCase))
cmd.AppendSwitch ("--debug");

// generating proguard application configuration
if (EnableTreeShaking) {
var acwLines = File.ReadAllLines (AcwMapFile);
using (var appcfg = File.CreateText (ProguardGeneratedApplicationConfiguration))
for (int i = 0; i + 2 < acwLines.Length; i += 3)
try {
var line = acwLines [i + 2];
var java = line.Substring (line.IndexOf (';') + 1);
appcfg.WriteLine ("-keep class " + java + " { *; }");
} catch {
// skip invalid lines
}
if (!string.IsNullOrWhiteSpace (ProguardCommonXamarinConfiguration))
using (var xamcfg = File.Create (ProguardCommonXamarinConfiguration))
GetType ().Assembly.GetManifestResourceStream ("proguard_xamarin.cfg").CopyTo (xamcfg);
var configs = ProguardConfigurationFiles
.Replace ("{sdk.dir}", AndroidSdkDirectory + Path.DirectorySeparatorChar)
.Replace ("{intermediate.common.xamarin}", ProguardCommonXamarinConfiguration)
.Replace ("{intermediate.references}", ProguardGeneratedReferenceConfiguration)
.Replace ("{intermediate.application}", ProguardGeneratedApplicationConfiguration)
.Replace ("{project}", string.Empty) // current directory anyways.
.Split (';')
.Select (s => s.Trim ())
.Where (s => !string.IsNullOrWhiteSpace (s));
foreach (var file in configs) {
if (File.Exists (file))
cmd.AppendSwitchIfNotNull ("--pg-conf ", file);
else
Log.LogCodedWarning ("XA4304", file, 0, "Proguard configuration file '{0}' was not found.", file);
}
cmd.AppendSwitchIfNotNull ("--pg-map-output ", ProguardMappingOutput);
}

// multidexing
if (EnableMultiDex) {
if (string.IsNullOrEmpty (MultiDexMainDexListFile)) {
Log.LogCodedWarning ("XA4305", $"MultiDex is enabled, but '{nameof (MultiDexMainDexListFile)}' was not specified.");
} else if (!File.Exists (MultiDexMainDexListFile)) {
Log.LogCodedWarning ("XA4305", MultiDexMainDexListFile, 0, $"MultiDex is enabled, but main dex list file '{MultiDexMainDexListFile}' does not exist.");
} else {
cmd.AppendSwitchIfNotNull ("--main-dex-list ", MultiDexMainDexListFile);
}
}

// desugaring
var doc = AndroidAppManifest.Load (AndroidManifestFile, MonoAndroidHelper.SupportedVersions);
int minApiVersion = doc.MinSdkVersion == null ? 4 : (int)doc.MinSdkVersion;
cmd.AppendSwitchIfNotNull ("--min-api ", minApiVersion.ToString ());

if (!EnableTreeShaking)
cmd.AppendSwitch ("--no-tree-shaking");
if (!EnableDesugar)
cmd.AppendSwitch ("--no-desugaring");
if (!EnableMinify)
cmd.AppendSwitch ("--no-minification");

var injars = new List<string> ();
var libjars = new List<string> ();
injars.Add (ClassesZip);
if (JavaLibrariesToEmbed != null)
foreach (var jarfile in JavaLibrariesToEmbed)
injars.Add (jarfile.ItemSpec);
libjars.Add (JavaPlatformJarPath);
if (JavaLibrariesToReference != null)
foreach (var jarfile in JavaLibrariesToReference.Select (p => p.ItemSpec))
libjars.Add (jarfile);

cmd.AppendSwitchIfNotNull ("--output ", OutputDirectory);
foreach (var jar in libjars)
cmd.AppendSwitchIfNotNull ("--lib ", jar);
foreach (var jar in injars)
cmd.AppendFileNameIfNotNull (jar);

return cmd.ToString ();
}
}

}
Loading

0 comments on commit 151db1a

Please sign in to comment.