Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] Support multidex + ' ' in SDK path (#575)
Browse files Browse the repository at this point in the history
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=33052
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=38693

The google tooling around multidex is pretty broken on
windows. It does not handle paths with spaces and has
over quoting path issues. This is one reason why we are
shipping our own Proguard.

This commit completely removes the use of `mainDexClasses.bat`
and introduces code which will create the ` multidex.keep` by
making the required calls manually.
  • Loading branch information
dellis1972 authored and jonpryor committed Apr 28, 2017
1 parent 611bb66 commit 6829b7d
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2011 Xamarin, Inc. All rights reserved.
// Copyright (C) 2011 Xamarin, Inc. All rights reserved.

using System;
using System.Collections.Generic;
Expand All @@ -12,20 +12,27 @@

namespace Xamarin.Android.Tasks
{
public class CreateMultiDexMainDexClassList : ToolTask
public class CreateMultiDexMainDexClassList : JavaToolTask
{
[Required]
public string ClassesOutputDirectory { get; set; }

[Required]
public string ProguardHome { get; set; }
public string ProguardJarPath { get; set; }

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

[Required]
public ITaskItem[] JavaLibraries { get; set; }

public string MultiDexMainDexListFile { get; set; }
public ITaskItem[] CustomMainDexListFiles { get; set; }

Action<CommandLineBuilder> commandlineAction;
string tempJar;
bool writeOutputToKeepFile = false;

public override bool Execute ()
{
Log.LogDebugMessage ("CreateMultiDexMainDexClassList");
Expand All @@ -35,45 +42,69 @@ public override bool Execute ()
Log.LogDebugTaskItems (" CustomMainDexListFiles:", CustomMainDexListFiles);
Log.LogDebugMessage (" ToolExe: {0}", ToolExe);
Log.LogDebugMessage (" ToolPath: {0}", ToolPath);
Log.LogDebugMessage (" ProguardHome: {0}", ProguardHome);
Log.LogDebugMessage (" ProguardJarPath: {0}", ProguardJarPath);

if (CustomMainDexListFiles != null && CustomMainDexListFiles.Any ()) {
var content = string.Concat (CustomMainDexListFiles.Select (i => File.ReadAllText (i.ItemSpec)));
File.WriteAllText (MultiDexMainDexListFile, content);
return true;
}

EnvironmentVariables = MonoAndroidHelper.GetProguardEnvironmentVaribles (ProguardHome);
tempJar = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName () + ".jar");
commandlineAction = GenerateProguardCommands;
// run proguard first
var retval = base.Execute ();
if (!retval || Log.HasLoggedErrors)
return false;

commandlineAction = GenerateMainDexListBuilderCommands;
// run java second

return base.Execute () && !Log.HasLoggedErrors;

return base.Execute ();
}

protected override string GenerateCommandLineCommands ()
{
var cmd = new CommandLineBuilder ();
commandlineAction (cmd);
return cmd.ToString ();
}

cmd.AppendSwitch ("--output");
cmd.AppendFileNameIfNotNull (MultiDexMainDexListFile);

void GenerateProguardCommands (CommandLineBuilder cmd)
{
var enclosingChar = OS.IsWindows ? "\"" : string.Empty;
var jars = JavaLibraries.Select (i => i.ItemSpec).Concat (new string [] { ClassesOutputDirectory });
string files = string.Join (Path.PathSeparator.ToString (), jars.Select (s => '\'' + s + '\''));
if (OS.IsWindows)
cmd.AppendSwitch ('"' + files + '"');
else
cmd.AppendSwitch (files);

return cmd.ToString ();
cmd.AppendSwitchIfNotNull ("-jar ", ProguardJarPath);
cmd.AppendSwitchUnquotedIfNotNull ("-injars ", $"{enclosingChar}'" + string.Join ($"'{Path.PathSeparator}'", jars) + $"'{enclosingChar}");
cmd.AppendSwitch ("-dontwarn");
cmd.AppendSwitch ("-forceprocessing");
cmd.AppendSwitchIfNotNull ("-outjars ", tempJar);
cmd.AppendSwitchIfNotNull ("-libraryjars ", $"'{Path.Combine (AndroidSdkBuildToolsPath, "lib", "shrinkedAndroid.jar")}'");
cmd.AppendSwitch ("-dontoptimize");
cmd.AppendSwitch ("-dontobfuscate");
cmd.AppendSwitch ("-dontpreverify");
cmd.AppendSwitchIfNotNull ("-include ", $"'{Path.Combine (AndroidSdkBuildToolsPath, "mainDexClasses.rules")}'");
}

protected override string ToolName {
get {
return OS.IsWindows ? "mainDexClasses.bat" : "mainDexClasses";
}
void GenerateMainDexListBuilderCommands(CommandLineBuilder cmd)
{
var jars = JavaLibraries.Select (i => i.ItemSpec).Concat (new string [] { ClassesOutputDirectory });
cmd.AppendSwitchIfNotNull ("-Djava.ext.dirs=", Path.Combine (AndroidSdkBuildToolsPath, "lib"));
cmd.AppendSwitch ("com.android.multidex.MainDexListBuilder");
cmd.AppendSwitch (tempJar);
cmd.AppendSwitchUnquotedIfNotNull ("", "\"" + string.Join ($"{Path.PathSeparator}", jars) + "\"");
writeOutputToKeepFile = true;
}

protected override string GenerateFullPathToTool ()
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
{
return Path.Combine (ToolPath, ToolExe);
var match = CodeErrorRegEx.Match (singleLine);
var exceptionMatch = ExceptionRegEx.Match (singleLine);

if (writeOutputToKeepFile && !match.Success && !exceptionMatch.Success)
File.AppendAllText (MultiDexMainDexListFile, singleLine);
base.LogEventsFromTextOutput (singleLine, messageImportance);
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/Xamarin.Android.Build.Tasks/Tasks/JavaToolTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ at com.android.dx.command.dexer.Main.main(Main.java:215)
at com.android.dx.command.Main.main(Main.java:106)
*/
const string ExceptionRegExString = @"(?<exception>java.lang.+):(?<error>.+)";
Regex codeErrorRegEx = new Regex (CodeErrorRegExString, RegexOptions.Compiled);
Regex exceptionRegEx = new Regex (ExceptionRegExString, RegexOptions.Compiled);
protected static readonly Regex CodeErrorRegEx = new Regex (CodeErrorRegExString, RegexOptions.Compiled);
protected static readonly Regex ExceptionRegEx = new Regex (ExceptionRegExString, RegexOptions.Compiled);
bool foundError = false;
List<string> errorLines = new List<string> ();
StringBuilder errorText = new StringBuilder ();
Expand Down Expand Up @@ -114,8 +114,8 @@ void LogFromException (string exception, string error) {

bool ProcessOutput (string singleLine)
{
var match = codeErrorRegEx.Match (singleLine);
var exceptionMatch = exceptionRegEx.Match (singleLine);
var match = CodeErrorRegEx.Match (singleLine);
var exceptionMatch = ExceptionRegEx.Match (singleLine);

if (match.Success) {
if (!string.IsNullOrEmpty (file)) {
Expand Down Expand Up @@ -157,8 +157,8 @@ bool ProcessOutput (string singleLine)

protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
{
var match = codeErrorRegEx.Match (singleLine);
var exceptionMatch = exceptionRegEx.Match (singleLine);
var match = CodeErrorRegEx.Match (singleLine);
var exceptionMatch = ExceptionRegEx.Match (singleLine);

if (match.Success || exceptionMatch.Success) {
Log.LogMessage (MessageImportance.High, singleLine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1950,9 +1950,10 @@ because xbuild doesn't support framework reference assemblies.

<CreateMultiDexMainDexClassList
Condition="'$(AndroidEnableMultiDex)' == 'True' And '$(AndroidCustomMainDexListFile)' == ''"
ToolPath="$(MainDexClassesToolPath)"
ToolExe="$(MainDexClassesToolExe)"
ProguardHome="$(ProguardToolPath)"
ToolPath="$(JavaToolPath)"
ToolExe="$(JavaToolExe)"
ProguardJarPath="$(ProguardJarPath)"
AndroidSdkBuildToolsPath="$(AndroidSdkBuildToolsPath)"
ClassesOutputDirectory="$(IntermediateOutputPath)android\bin\classes"
JavaLibraries="@(_JavaLibrariesToCompile)"
MultiDexMainDexListFile="$(_AndroidMainDexListFile)"
Expand Down

0 comments on commit 6829b7d

Please sign in to comment.