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 4, 2018
1 parent 9f4b0df commit 1b19111
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 25 deletions.
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
167 changes: 167 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/R8.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// 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 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.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 (!string.IsNullOrWhiteSpace (MultiDexMainDexListFile) && File.Exists (MultiDexMainDexListFile))
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 ();
}
}

}
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
75 changes: 72 additions & 3 deletions src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
<UsingTask TaskName="Xamarin.Android.Tasks.Javac" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.Desugar" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.Dx" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.R8" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.KeyTool" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.LinkAssemblies" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.Lint" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
Expand Down Expand Up @@ -264,6 +265,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
<AndroidEnableProguard Condition="'$(AndroidEnableProguard)'==''">$(EnableProguard)</AndroidEnableProguard>
<AndroidEnableMultiDex Condition="'$(AndroidEnableMultiDex)'==''">False</AndroidEnableMultiDex>
<AndroidEnableDesugar Condition="'$(AndroidEnableDesugar)'==''">False</AndroidEnableDesugar>
<AndroidUseR8 Condition="'$(AndroidUseR8)'==''">False</AndroidUseR8>

<!-- Default Java heap size to 1GB (-Xmx1G) if not specified-->
<JavaMaximumHeapSize Condition=" '$(JavaMaximumHeapSize)' == '' ">1G</JavaMaximumHeapSize>
Expand Down Expand Up @@ -853,12 +855,36 @@ because xbuild doesn't support framework reference assemblies.
/>
</CreateProperty>

<CreateProperty Condition="'$(AndroidEnableD8)' == 'True'" Value="$(MonoAndroidToolsDirectory)\d8.jar">
<Output TaskParameter="Value" PropertyName="DxJarPath"
Condition="'$(DxJarPath)' == ''"
/>
</CreateProperty>

<CreateProperty Value="$(MonoAndroidToolsDirectory)\desugar_deploy.jar">
<Output TaskParameter="Value" PropertyName="DesugarJarPath"
Condition="'$(DesugarJarPath)' == ''"
/>
</CreateProperty>

<CreateProperty Value="$(MonoAndroidToolsDirectory)\r8.jar">
<Output TaskParameter="Value" PropertyName="R8JarPath"
Condition="'$(R8JarPath)' == ''"
/>
</CreateProperty>

<CreateProperty Value="--debug">
<Output TaskParameter="Value" PropertyName="DxExtraArguments"
Condition="'$(DxExtraArguments)' == '' And '$(AndroidEnableD8)' == 'True' And '$(Configuration)' == 'Debug'"
/>
</CreateProperty>

<CreateProperty Value="--release">
<Output TaskParameter="Value" PropertyName="DxExtraArguments"
Condition="'$(DxExtraArguments)' == '' And '$(AndroidEnableD8)' == 'True' And '$(Configuration)' != 'Debug'"
/>
</CreateProperty>

<CreateProperty Value="--dex --no-strict">
<Output TaskParameter="Value" PropertyName="DxExtraArguments"
Condition="'$(DxExtraArguments)' == ''"
Expand Down Expand Up @@ -2177,6 +2203,7 @@ because xbuild doesn't support framework reference assemblies.
</PropertyGroup>

<Target Name="_CompileToDalvikWithDx"
Condition="'$(AndroidUseR8)' != 'True'"
DependsOnTargets="$(_CompileToDalvikDependsOnTargets)"
Inputs="$(_CompileToDalvikInputs)"
Outputs="$(IntermediateOutputPath)_dex_stamp">
Expand Down Expand Up @@ -2227,8 +2254,7 @@ because xbuild doesn't support framework reference assemblies.
ProguardGeneratedApplicationConfiguration="$(IntermediateOutputPath)proguard\proguard_project_primary.cfg"
ProguardConfigurationFiles="$(ProguardConfigFiles)"
JavaLibrariesToEmbed="@(_JarsToProguard);@(_InstantRunJavaReference)"
ExternalJavaLibraries="@(AndroidExternalJavaLibrary)"
DoNotPackageJavaLibraries="@(_ResolvedDoNotPackageAttributes)"
JavaLibrariesToReference="@(AndroidExternalJavaLibrary)"
ProguardJarOutput="$(IntermediateOutputPath)proguard\__proguard_output__.jar"
EnableLogging="$(ProguardEnableLogging)"
DumpOutput="$(IntermediateOutputPath)proguard\dump.txt"
Expand Down Expand Up @@ -2286,8 +2312,51 @@ because xbuild doesn't support framework reference assemblies.

</Target>

<Target Name="_CompileToDalvikWithR8"
Condition="'$(AndroidUseR8)' == 'True'"
DependsOnTargets="$(_CompileToDalvikDependsOnTargets)"
Inputs="$(_CompileToDalvikInputs)"
Outputs="$(IntermediateOutputPath)_dex_stamp">

<Error
Condition="!Exists('$(R8JarPath)')"
Text="r8.jar does not exist (R8JarPath property has to point to a valid file (current value: '$(R8JarPath)')." />

<!-- remove existing dex files that may be previous multidex outputs. -->
<Delete Files="$(IntermediateOutputPath)android\bin\classes\*.dex" />

<MakeDir Directories="$(IntermediateOutputPath)proguard" />

<R8
ToolPath="$(JavaToolPath)"
JavaMaximumHeapSize="$(JavaMaximumHeapSize)"
JavaOptions="$(JavaOptions)"
R8JarPath="$(R8JarPath)"
AndroidManifestFile="$(IntermediateOutputPath)android\AndroidManifest.xml"
OutputDirectory="$(IntermediateOutputPath)android\"
Configuration="$(Configuration)"
JavaPlatformJarPath="$(JavaPlatformJarPath)"
ClassesZip="$(IntermediateOutputPath)android\bin\classes.zip"
JavaLibrariesToEmbed="@(_JavaLibrariesToCompile);@(_InstantRunJavaReference)"
JavaLibrariesToReference="@(AndroidExternalJavaLibrary)"
EnableDesugar="$(AndroidEnableDesugar)"
EnableTreeShaking="$(AndroidEnableProguard)"
AndroidSdkDirectory="$(_AndroidSdkDirectory)"
AcwMapFile="$(_AcwMapFile)"
ProguardCommonXamarinConfiguration="$(IntermediateOutputPath)proguard\proguard_xamarin.cfg"
ProguardGeneratedReferenceConfiguration="$(_ProguardProjectConfiguration)"
ProguardGeneratedApplicationConfiguration="$(IntermediateOutputPath)proguard\proguard_project_primary.cfg"
ProguardConfigurationFiles="$(ProguardConfigFiles)"
MultiDexMainDexListFile="$(_AndroidMainDexListFile)"
R8ExtraArguments="$(R8ExtraArguments)"
/>

<Touch Files="$(IntermediateOutputPath)_dex_stamp" AlwaysCreate="true" />

</Target>

<Target Name="_CompileDex"
DependsOnTargets="_CompileToDalvikWithDx">
DependsOnTargets="_CompileToDalvikWithDx;_CompileToDalvikWithR8">

<ItemGroup>
<_DexFile Include="$(IntermediateOutputPath)android\bin\dex\*.dex" />
Expand Down
File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions build-tools/r8/r8.targets → src/r8/r8.targets
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
</Target>

<Target Name="_CopyR8">
<Copy
SourceFiles="..\..\external\r8\build\libs\d8.jar"
DestinationFolder="$(XAInstallPrefix)\xbuild\Xamarin\Android\"
SkipUnchangedFiles="true"
/>
<Copy
SourceFiles="..\..\external\r8\build\libs\r8.jar"
DestinationFolder="$(XAInstallPrefix)\xbuild\Xamarin\Android\"
Expand Down

0 comments on commit 1b19111

Please sign in to comment.