Skip to content

Commit

Permalink
[msbuild][r8] add r8 support to alter dx, proguard and desugar.
Browse files Browse the repository at this point in the history
See #1423 for details.

multidex support is not done yet (needs to investigate what's expected there).
  • Loading branch information
atsushieno committed Apr 18, 2018
1 parent 31abb13 commit d228827
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 28 deletions.
2 changes: 2 additions & 0 deletions Xamarin.Android.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "android-toolchain", "build-
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools.BootstrapTasks", "build-tools\Xamarin.Android.Tools.BootstrapTasks\Xamarin.Android.Tools.BootstrapTasks.csproj", "{E8492EFB-D14A-4F32-AA28-88848322ECEA}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "r8", "src\r8\r8.csproj", "{1bafa0cc-0377-46ce-ab7b-7bb2e7b62f63}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "mono-runtimes", "src\mono-runtimes\mono-runtimes.csproj", "{C03E6CF1-7460-4CDC-A4AB-292BBC0F61F2}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "libzip", "src\libzip\libzip.csproj", "{900A0F71-BAAD-417A-8D1A-8D330297CDD0}"
Expand Down
9 changes: 9 additions & 0 deletions external/depot_tools.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/depot_tools">
<LicenseFile>$(MSBuildThisFileDirectory)\depot_tools\LICENSE</LicenseFile>
<SourceUrl>https://chromium.googlesource.com/chromium/tools/depot_tools.git</SourceUrl>
</ThirdPartyNotice>
</ItemGroup>
</Project>
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 @@ -19,6 +19,8 @@
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<AndroidUseR8>true</AndroidUseR8>
<AndroidEnableD8>true</AndroidEnableD8>
</PropertyGroup>
<Import Project="..\..\..\Configuration.props" />
<PropertyGroup>
Expand Down
37 changes: 15 additions & 22 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 @@ -86,14 +80,13 @@ public override bool Execute ()
Log.LogDebugMessage (" JavaPlatformJarPath: {0}", JavaPlatformJarPath);
Log.LogDebugMessage (" ClassesOutputDirectory: {0}", ClassesOutputDirectory);
Log.LogDebugMessage (" AcwMapFile: {0}", AcwMapFile);
Log.LogDebugMessage (" ProguardGeneratedApplicationConfiguration: {0}", ProguardGeneratedApplicationConfiguration);
Log.LogDebugMessage (" ProguardJarOutput: {0}", ProguardJarOutput);
Log.LogDebugTaskItems (" ProguardGeneratedReferenceConfiguration:", ProguardGeneratedReferenceConfiguration);
Log.LogDebugTaskItems (" ProguardGeneratedApplicationConfiguration:", ProguardGeneratedApplicationConfiguration);
Log.LogDebugTaskItems (" ProguardCommonXamarinConfiguration:", ProguardCommonXamarinConfiguration);
Log.LogDebugTaskItems (" ProguardConfigurationFiles:", ProguardConfigurationFiles);
Log.LogDebugTaskItems (" ExternalJavaLibraries:", ExternalJavaLibraries);
Log.LogDebugTaskItems (" DoNotPackageJavaLibraries:", DoNotPackageJavaLibraries);
Log.LogDebugTaskItems (" JavaLibrariesToEmbed:", JavaLibrariesToEmbed);
Log.LogDebugTaskItems (" JavaLibrariesToReference:", JavaLibrariesToReference);
Log.LogDebugMessage (" UseProguard: {0}", UseProguard);
Log.LogDebugMessage (" EnableLogging: {0}", EnableLogging);
Log.LogDebugMessage (" DumpOutput: {0}", DumpOutput);
Expand Down Expand Up @@ -139,15 +132,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 @@ -168,9 +155,15 @@ protected override string GenerateCommandLineCommands ()
Log.LogWarning ("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
173 changes: 173 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/R8.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// 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.Text;
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; }

public override bool Execute ()
{
Log.LogDebugMessage ("R8 Task");
Log.LogDebugTaskItems (" R8JarPath: ", R8JarPath);
Log.LogDebugTaskItems (" OutputDirectory: ", OutputDirectory);
Log.LogDebugTaskItems (" AndroidManifestFile: ", AndroidManifestFile);
Log.LogDebugMessage (" Configuration: {0}", Configuration);
Log.LogDebugTaskItems (" JavaPlatformJarPath: ", JavaPlatformJarPath);
Log.LogDebugTaskItems (" ClassesZip: ", ClassesZip);
Log.LogDebugTaskItems (" JavaLibrariesToEmbed: ", JavaLibrariesToEmbed);
Log.LogDebugTaskItems (" JavaLibrariesToReference: ", JavaLibrariesToReference);
Log.LogDebugMessage (" EnableDesugar: {0}", EnableDesugar);
Log.LogDebugMessage (" EnableTreeShaking: {0}", EnableTreeShaking);
Log.LogDebugTaskItems (" AndroidSdkDirectory:", AndroidSdkDirectory);
Log.LogDebugTaskItems (" AcwMapFile: ", AcwMapFile);
Log.LogDebugTaskItems (" ProguardGeneratedReferenceConfiguration:", ProguardGeneratedReferenceConfiguration);
Log.LogDebugTaskItems (" ProguardGeneratedApplicationConfiguration:", ProguardGeneratedApplicationConfiguration);
Log.LogDebugTaskItems (" ProguardCommonXamarinConfiguration:", ProguardCommonXamarinConfiguration);
Log.LogDebugTaskItems (" ProguardConfigurationFiles:", ProguardConfigurationFiles);
Log.LogDebugTaskItems (" ProguardMappingOutput:", ProguardMappingOutput);
Log.LogDebugMessage (" EnableMultiDex: {0}", EnableMultiDex);
Log.LogDebugTaskItems (" MultiDexMainDexListFile: ", MultiDexMainDexListFile);
Log.LogDebugTaskItems (" R8ExtraArguments: ", R8ExtraArguments);

return base.Execute ();
}

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));
var enclosingChar = "\"";
foreach (var file in configs) {
if (File.Exists (file))
cmd.AppendSwitchUnquotedIfNotNull ("--pg-conf ", $"{enclosingChar}{file}{enclosingChar}");
else
Log.LogWarning ("Proguard configuration file '{0}' was not found.", file);
}
cmd.AppendSwitchIfNotNull ("--pg-map-output ", ProguardMappingOutput);

// multidexing
if (EnableMultiDex) {
if (!string.IsNullOrWhiteSpace (MultiDexMainDexListFile) && File.Exists (MultiDexMainDexListFile))
cmd.AppendSwitchIfNotNull ("--main-dex-list ", MultiDexMainDexListFile);
else
Log.LogWarning ($"MultiDex is enabled, but main dex list file '{MultiDexMainDexListFile}' does not exist.");
}
}

// 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 ();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,49 @@ public partial class BuildTest : BaseTest
/* isRelease */ true,
/* enableProguard */ true,
/* useLatestSdk */ true,
/* useR8 */ false,
},
new Object [] {
/* isRelease */ true,
/* enableProguard */ false,
/* useLatestSdk */ true,
/* useR8 */ false,
},
new Object [] {
/* isRelease */ false,
/* enableProguard */ true,
/* useLatestSdk */ true,
/* useR8 */ false,
},
new Object [] {
/* isRelease */ false,
/* enableProguard */ false,
/* useLatestSdk */ true,
/* useR8 */ false,
},
new Object [] {
/* isRelease */ true,
/* enableProguard */ true,
/* useLatestSdk */ true,
/* useR8 */ true,
},
new Object [] {
/* isRelease */ true,
/* enableProguard */ false,
/* useLatestSdk */ true,
/* useR8 */ true,
},
new Object [] {
/* isRelease */ false,
/* enableProguard */ true,
/* useLatestSdk */ true,
/* useR8 */ true,
},
new Object [] {
/* isRelease */ false,
/* enableProguard */ false,
/* useLatestSdk */ true,
/* useR8 */ true,
},
};
static object [] TakeSimpleFlag = new object [] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,10 +445,10 @@ public void BuildAotApplicationAndBundle (string supportedAbis, bool enableLLVM,

[Test]
[TestCaseSource ("ProguardChecks")]
public void BuildProguardEnabledProject (bool isRelease, bool enableProguard, bool useLatestSdk)
public void BuildProguardEnabledProject (bool isRelease, bool enableProguard, bool useLatestSdk, bool useR8)
{
var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, EnableProguard = enableProguard, UseLatestPlatformSdk = useLatestSdk, TargetFrameworkVersion = useLatestSdk ? "v7.1" : "v5.0" };
using (var b = CreateApkBuilder (Path.Combine ("temp", $"BuildProguard Enabled Project(1){isRelease}{enableProguard}{useLatestSdk}"))) {
var proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, EnableProguard = enableProguard, UseR8 = useR8, UseLatestPlatformSdk = useLatestSdk, TargetFrameworkVersion = useLatestSdk ? "v7.1" : "v5.0" };
using (var b = CreateApkBuilder (Path.Combine ("temp", $"BuildProguard Enabled Project(1){isRelease}{enableProguard}{useLatestSdk}{useR8}"))) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");

if (isRelease && enableProguard) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public static class KnownProperties
public const string BundleAssemblies = "BundleAssemblies";
public const string EnableProguard = "EnableProguard";
public const string AndroidEnableDesugar = "AndroidEnableDesugar";
public const string AndroidUseR8 = "AndroidUseR8";
public const string UseJackAndJill = "UseJackAndJill";
public const string AotAssemblies = "AotAssemblies";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public bool EnableDesugar {
set { SetProperty (KnownProperties.AndroidEnableDesugar, value.ToString ()); }
}

public bool UseR8 {
get { return string.Equals (GetProperty (KnownProperties.AndroidUseR8), "True", StringComparison.OrdinalIgnoreCase); }
set { SetProperty (KnownProperties.AndroidUseR8, value.ToString ()); }
}

public string AndroidFastDeploymentType {
get { return GetProperty (KnownProperties.AndroidFastDeploymentType); }
set { SetProperty (KnownProperties.AndroidFastDeploymentType, value); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,9 @@
<Compile Include="Utilities\SatelliteAssembly.cs" />
<Compile Include="Tasks\AndroidApkSigner.cs" />
<Compile Include="Tasks\Desugar.cs" />
<Compile Include="Tasks\R8.cs" />
<Compile Include="Utilities\NuGetLogger.cs" />
<None Include="*.targets" />
<None Include="Resources\desugar_deploy.jar">
<Link>desugar_deploy.jar</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down Expand Up @@ -693,6 +695,11 @@
<Name>proguard</Name>
<ReferenceOutputAssembly>False</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\r8\r8.csproj">
<Project>{1bafa0cc-0377-46ce-ab7b-7bb2e7b62f63}</Project>
<Name>r8</Name>
<ReferenceOutputAssembly>False</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\external\LibZipSharp\libZipSharp.csproj">
<Project>{E248B2CA-303B-4645-ADDC-9D4459D550FD}</Project>
<Name>libZipSharp</Name>
Expand Down
Loading

0 comments on commit d228827

Please sign in to comment.