From bb0b208cf74d78a778f7b1ea42e105b9a9f9714d Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Wed, 9 Aug 2017 10:03:18 +0100 Subject: [PATCH] [Xamarin.Android.Build.Tasks] [VSM][Android] Build error observed with MultiDex + Custom configuration have spaces. Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=58134 We did a ton of stuff to get multidex working correctly on windows in commit 6829b7d1. However it seems that if there are spaces in the path on MacOS, we get similar problems. The solution is to add single quotes around the list of .jar files when calling the MainDexListBuilder. That seems pretty logical. But... it breaks it on windows (sigh). Because on windows if we add the single quotes, it stops working. So we have to conditionally add the single quotes around the list of jar files. Not this only applies when we call the MainDexListBuilder. The single quotes seem to work ok when calling proguard.. Weird. This commit also adds a unit test for this. However we needed to be able to change the names of the Configurations "Debug", "Release". So contructor arguments have been added to allow them to be overridden. These will default to "Debug" and "Release" so that existing tests will work as expected. --- .../Tasks/CreateMultiDexMainDexClassList.cs | 9 ++++--- .../Xamarin.Android.Build.Tests/BuildTest.cs | 17 +++++++++--- .../XamarinAndroidApplicationProject.cs | 3 ++- .../Android/XamarinAndroidBindingProject.cs | 3 ++- .../Android/XamarinAndroidCommonProject.cs | 3 ++- .../Android/XamarinAndroidLibraryProject.cs | 3 ++- .../Android/XamarinAndroidProject.cs | 3 ++- .../XamarinAndroidWearApplicationProject.cs | 3 ++- .../Xamarin.ProjectTools/Common/Builder.cs | 12 ++++----- .../Common/XamarinProject.cs | 27 ++++++++++++------- 10 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CreateMultiDexMainDexClassList.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CreateMultiDexMainDexClassList.cs index 847d931bd94..355ebfa9e97 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CreateMultiDexMainDexClassList.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CreateMultiDexMainDexClassList.cs @@ -89,12 +89,15 @@ void GenerateProguardCommands (CommandLineBuilder cmd) void GenerateMainDexListBuilderCommands(CommandLineBuilder cmd) { - var enclosingChar = OS.IsWindows ? "\"" : string.Empty; + var enclosingDoubleQuote = OS.IsWindows ? "\"" : string.Empty; + var enclosingQuote = OS.IsWindows ? string.Empty : "'"; 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 ($"{enclosingChar}{tempJar}{enclosingChar}"); - cmd.AppendSwitchUnquotedIfNotNull ("", $"{enclosingChar}" + string.Join ($"{Path.PathSeparator}", jars) + $"{enclosingChar}"); + cmd.AppendSwitch ($"{enclosingDoubleQuote}{tempJar}{enclosingDoubleQuote}"); + cmd.AppendSwitchUnquotedIfNotNull ("", $"{enclosingDoubleQuote}{enclosingQuote}" + + string.Join ($"{enclosingQuote}{Path.PathSeparator}{enclosingQuote}", jars) + + $"{enclosingQuote}{enclosingDoubleQuote}"); writeOutputToKeepFile = true; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index 1ee2f6f81bd..c1311c161ac 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -300,9 +300,9 @@ public void BuildProguardEnabledProject (bool isRelease, bool enableProguard, bo } } - XamarinAndroidApplicationProject CreateMultiDexRequiredApplication () + XamarinAndroidApplicationProject CreateMultiDexRequiredApplication (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") { - var proj = new XamarinAndroidApplicationProject (); + var proj = new XamarinAndroidApplicationProject (debugConfigurationName, releaseConfigurationName); proj.OtherBuildItems.Add (new BuildItem (AndroidBuildActions.AndroidJavaSource, "ManyMethods.java") { TextContent = () => "public class ManyMethods { \n" + string.Join (Environment.NewLine, Enumerable.Range (0, 32768).Select (i => "public void method" + i + "() {}")) @@ -330,6 +330,17 @@ public void BuildApplicationOver65536Methods () } } + [Test] + public void CreateMultiDexWithSpacesInConfig () + { + var proj = CreateMultiDexRequiredApplication (releaseConfigurationName: "Test Config"); + proj.IsRelease = true; + proj.SetProperty ("AndroidEnableMultiDex", "True"); + using (var b = CreateApkBuilder ("temp/CreateMultiDexWithSpacesInConfig")) { + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + } + } + [Test] [TestCaseSource ("JackFlagAndFxVersion")] public void BuildMultiDexApplication (bool useJackAndJill, string fxVersion) @@ -1949,7 +1960,7 @@ public void BuildAMassiveApp() TextContent = () => @"using System; namespace "+ libName + @" { - + public class " + libName + @" { public static void Foo () { } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs index 5aa82c937f9..a7aac09e2f6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs @@ -33,7 +33,8 @@ static XamarinAndroidApplicationProject () } - public XamarinAndroidApplicationProject () + public XamarinAndroidApplicationProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + : base (debugConfigurationName, releaseConfigurationName) { SetProperty ("AndroidApplication", "True"); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidBindingProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidBindingProject.cs index 3b5409de2b6..7990c1a5012 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidBindingProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidBindingProject.cs @@ -16,7 +16,8 @@ public override string ProjectTypeGuid { public IList Jars { get; private set; } public IList Transforms { get; private set; } - public XamarinAndroidBindingProject () + public XamarinAndroidBindingProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + : base (debugConfigurationName, releaseConfigurationName) { SetProperty ("MonoAndroidJavaPrefix", "Java"); SetProperty ("MonoAndroidTransformPrefix", "Transforms"); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs index 8bf4426706b..c6e44e4d71e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidCommonProject.cs @@ -51,7 +51,8 @@ static XamarinAndroidCommonProject () } } - protected XamarinAndroidCommonProject () + protected XamarinAndroidCommonProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + : base (debugConfigurationName, releaseConfigurationName) { AndroidResources = new List (); ItemGroupList.Add (AndroidResources); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidLibraryProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidLibraryProject.cs index 6b0136181a3..bfa943a9933 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidLibraryProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidLibraryProject.cs @@ -15,7 +15,8 @@ public class XamarinAndroidLibraryProject : XamarinAndroidCommonProject "; - public XamarinAndroidLibraryProject () + public XamarinAndroidLibraryProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + : base (debugConfigurationName, releaseConfigurationName) { SetProperty ("AndroidApplication", "False"); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs index c620d9bfc24..7db82452a91 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidProject.cs @@ -9,7 +9,8 @@ namespace Xamarin.ProjectTools { public abstract class XamarinAndroidProject : XamarinProject { - protected XamarinAndroidProject () + protected XamarinAndroidProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + : base (debugConfigurationName, releaseConfigurationName) { Language = XamarinAndroidProjectLanguage.CSharp; TargetFrameworkVersion = Versions.Marshmallow; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidWearApplicationProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidWearApplicationProject.cs index b1bb785e564..ca70f9df536 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidWearApplicationProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidWearApplicationProject.cs @@ -24,7 +24,8 @@ static XamarinAndroidWearApplicationProject () default_layout_round_main = sr.ReadToEnd (); } - public XamarinAndroidWearApplicationProject () + public XamarinAndroidWearApplicationProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") + : base (debugConfigurationName, releaseConfigurationName) { TargetFrameworkVersion = Versions.KitkatWatch; UseLatestPlatformSdk = false; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs index d3f2eebeb10..16152a322ba 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs @@ -124,13 +124,13 @@ protected bool BuildInternal (string projectOrSolution, string target, string [] ndkPath = Path.GetFullPath (Path.Combine (androidSdkToolPath, "ndk")); StringBuilder args = new StringBuilder (); var psi = new ProcessStartInfo (MSBuildExe); - if (Directory.Exists (sdkPath)) { - args.AppendFormat ("/p:AndroidSdkDirectory=\"{0}\" ", sdkPath); - } - if (Directory.Exists (ndkPath)) { - args.AppendFormat ("/p:AndroidNdkDirectory=\"{0}\" ", ndkPath); - } if (RunXBuild) { + if (Directory.Exists (sdkPath)) { + args.AppendFormat ("/p:AndroidSdkDirectory=\"{0}\" ", sdkPath); + } + if (Directory.Exists (ndkPath)) { + args.AppendFormat ("/p:AndroidNdkDirectory=\"{0}\" ", ndkPath); + } var outdir = Path.GetFullPath (Path.Combine (FrameworkLibDirectory, "..", "..")); var targetsdir = Path.Combine (FrameworkLibDirectory, "xbuild"); args.AppendFormat (" {0} ", logger); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs index 37f84a9d63e..efab92cf46c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/XamarinProject.cs @@ -19,10 +19,16 @@ public abstract class XamarinProject public ProjectLanguage Language { get; set; } - protected XamarinProject () + string debugConfigurationName; + string releaseConfigurationName; + + protected XamarinProject (string debugConfigurationName = "Debug", string releaseConfigurationName = "Release") { ProjectName = "UnnamedProject"; + this.debugConfigurationName = debugConfigurationName; + this.releaseConfigurationName = releaseConfigurationName; + Sources = new List (); References = new List (); OtherBuildItems = new List (); @@ -37,9 +43,9 @@ protected XamarinProject () CommonProperties = new List (); common = new PropertyGroup (null, CommonProperties); DebugProperties = new List (); - debug = new PropertyGroup ("'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'", DebugProperties); + debug = new PropertyGroup ($"'$(Configuration)|$(Platform)' == '{debugConfigurationName}|AnyCPU'", DebugProperties); ReleaseProperties = new List (); - release = new PropertyGroup ("'$(Configuration)|$(Platform)' == 'Release|AnyCPU'", ReleaseProperties); + release = new PropertyGroup ($"'$(Configuration)|$(Platform)' == '{releaseConfigurationName}|AnyCPU'", ReleaseProperties); PropertyGroups = new List (); PropertyGroups.Add (common); @@ -48,7 +54,7 @@ protected XamarinProject () Packages = new List (); - SetProperty (KnownProperties.Configuration, "Debug", "'$(Configuration)' == ''"); + SetProperty (KnownProperties.Configuration, debugConfigurationName, "'$(Configuration)' == ''"); SetProperty ("Platform", "AnyCPU", "'$(Platform)' == ''"); SetProperty ("ErrorReport", "prompt"); SetProperty ("WarningLevel", "4"); @@ -60,16 +66,16 @@ protected XamarinProject () SetProperty (DebugProperties, "DebugSymbols", "true"); SetProperty (DebugProperties, "DebugType", "full"); SetProperty (DebugProperties, "Optimize", "false"); - SetProperty (DebugProperties, KnownProperties.OutputPath, Path.Combine ("bin", "Debug")); + SetProperty (DebugProperties, KnownProperties.OutputPath, Path.Combine ("bin", debugConfigurationName)); SetProperty (DebugProperties, "DefineConstants", "DEBUG;"); - SetProperty (DebugProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", "Debug")); + SetProperty (DebugProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", debugConfigurationName)); SetProperty (ReleaseProperties, "Optimize", "true"); SetProperty (ReleaseProperties, "ErrorReport", "prompt"); SetProperty (ReleaseProperties, "WarningLevel", "4"); SetProperty (ReleaseProperties, "ConsolePause", "false"); - SetProperty (ReleaseProperties, KnownProperties.OutputPath, Path.Combine ("bin", "Release")); - SetProperty (ReleaseProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", "Release")); + SetProperty (ReleaseProperties, KnownProperties.OutputPath, Path.Combine ("bin", releaseConfigurationName)); + SetProperty (ReleaseProperties, KnownProperties.IntermediateOutputPath, Path.Combine ("obj", releaseConfigurationName)); Sources.Add (new BuildItem.Source (() => "Properties\\AssemblyInfo" + Language.DefaultExtension) { TextContent = () => ProcessSourceTemplate (AssemblyInfo ?? Language.DefaultAssemblyInfo) }); @@ -102,8 +108,8 @@ void AddProperties (IList list, string condition, KeyValuePair ActiveConfigurationProperties { @@ -277,6 +283,7 @@ public virtual List Save (bool saveProject = true) list.Add (new ProjectResource () { Path = import.Project (), Content = import.TextContent == null ? null : import.TextContent (), + Encoding = System.Text.Encoding.UTF8, }); return list;