From 2c835c52940fe020f3773f98921560708e00889b Mon Sep 17 00:00:00 2001 From: Chris Hamons Date: Wed, 8 Feb 2017 13:40:48 -0600 Subject: [PATCH] [XM] Add hybrid/standard AOT option and improve AOT code (#1650) * [XM] Seperate parsing from compilation in AOT code - Parsing command line options was too entangled with actually compiling - Refactor test code to centralize Compile, reducing some complexity of tests - Groundwork for hybrid vs non-hybrid AOT work * Add hybrid/standard AOT support * Add xammac_tests to makefile/jenkins * Add flag to force AOT * Disable MonoTouchFixtures.Contacts.ContactStoreTest.GetUnifiedContacts on XM due to prompts on Jenkins --- runtime/launcher.m | 4 +- runtime/runtime.m | 2 +- runtime/xamarin/main.h | 2 +- .../Contacts/ContactStoreTest.cs | 2 + tests/xammac_tests/xammac_tests.csproj | 4 +- tests/xharness/Harness.cs | 2 +- tools/mmp/aot.cs | 254 +++++++++++------- tools/mmp/driver.cs | 26 +- tools/mmp/tests/aot.cs | 163 +++++++---- 9 files changed, 293 insertions(+), 166 deletions(-) diff --git a/runtime/launcher.m b/runtime/launcher.m index 8e59ba7f13..e2d3229da2 100644 --- a/runtime/launcher.m +++ b/runtime/launcher.m @@ -567,7 +567,7 @@ int xamarin_main (int argc, char **argv, bool is_extension) int env_argc = 0; char **env_argv = get_mono_env_options (&env_argc); int new_argc = env_argc + 2 /* --debug executable */ + argc ; - if (xamarin_mac_aot) + if (xamarin_mac_hybrid_aot) new_argc += 1; char **new_argv = (char **) malloc (sizeof (char *) * (new_argc + 1 /* null terminated */)); const char **ptr = (const char **) new_argv; @@ -586,7 +586,7 @@ int xamarin_main (int argc, char **argv, bool is_extension) // executable assembly *ptr++ = exe_path; - if (xamarin_mac_aot) + if (xamarin_mac_hybrid_aot) *ptr++ = "--hybrid-aot"; // the rest diff --git a/runtime/runtime.m b/runtime/runtime.m index e93abedf40..46c085b922 100644 --- a/runtime/runtime.m +++ b/runtime/runtime.m @@ -45,7 +45,7 @@ bool xamarin_gc_pump = false; #if MONOMAC // FIXME: implement release mode for monomac. bool xamarin_debug_mode = true; -bool xamarin_mac_aot = false; +bool xamarin_mac_hybrid_aot = false; #else bool xamarin_debug_mode = false; #endif diff --git a/runtime/xamarin/main.h b/runtime/xamarin/main.h index 3f52cfa217..2ef4c7fa83 100644 --- a/runtime/xamarin/main.h +++ b/runtime/xamarin/main.h @@ -48,7 +48,7 @@ extern bool xamarin_gc_pump; extern bool xamarin_debug_mode; extern bool xamarin_disable_lldb_attach; #if MONOMAC -extern bool xamarin_mac_aot; +extern bool xamarin_mac_hybrid_aot; #endif extern bool xamarin_init_mono_debug; extern int xamarin_log_level; diff --git a/tests/monotouch-test/Contacts/ContactStoreTest.cs b/tests/monotouch-test/Contacts/ContactStoreTest.cs index 3086a9285e..31a7b744f2 100644 --- a/tests/monotouch-test/Contacts/ContactStoreTest.cs +++ b/tests/monotouch-test/Contacts/ContactStoreTest.cs @@ -34,7 +34,9 @@ namespace MonoTouchFixtures.Contacts { TestRuntime.AssertXcodeVersion (7, 0); } +#if !MONOMAC // Unlike XI, XM does not have infrastructure yet to disable prompts [Test] +#endif public void GetUnifiedContacts () { string identifier = null; diff --git a/tests/xammac_tests/xammac_tests.csproj b/tests/xammac_tests/xammac_tests.csproj index bc738164e0..dec8d152fd 100644 --- a/tests/xammac_tests/xammac_tests.csproj +++ b/tests/xammac_tests/xammac_tests.csproj @@ -16,7 +16,7 @@ true full false - bin\Debug + bin\x86\Debug __UNIFIED__;DEBUG;MONOMAC;XAMCORE_2_0 prompt 4 @@ -37,7 +37,7 @@ true - bin\Release + bin\x86\Release prompt 4 diff --git a/tests/xharness/Harness.cs b/tests/xharness/Harness.cs index 15ad29f96c..c8f55f82d0 100644 --- a/tests/xharness/Harness.cs +++ b/tests/xharness/Harness.cs @@ -279,7 +279,7 @@ namespace xharness MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (RootDirectory, "introspection", "Mac", "introspection-mac.csproj")), skipXMVariations : true)); - var hard_coded_test_suites = new string[] { "mmptest", "msbuild-mac" }; + var hard_coded_test_suites = new string[] { "mmptest", "msbuild-mac", "xammac_tests" }; foreach (var p in hard_coded_test_suites) MacTestProjects.Add (new MacTestProject (Path.GetFullPath (Path.Combine (RootDirectory, p + "/" + p + ".csproj")), generateVariations: false)); diff --git a/tools/mmp/aot.cs b/tools/mmp/aot.cs index 48038363c6..e061897062 100644 --- a/tools/mmp/aot.cs +++ b/tools/mmp/aot.cs @@ -56,7 +56,7 @@ namespace Xamarin.Bundler { public delegate int RunCommandDelegate (string path, string args, string[] env = null, StringBuilder output = null, bool suppressPrintOnErrors = false); - public enum MonoType { + public enum AOTCompilerType { Invalid, Bundled64, Bundled32, @@ -64,24 +64,115 @@ namespace Xamarin.Bundler { System32, } + public enum AOTCompilationType { + Default, + None, + All, + Core, + SDK, + Explicit + } + + public enum AOTKind { + Default, + Standard, + Hybrid + } + + public class AOTOptions + { + public bool IsAOT => CompilationType != AOTCompilationType.Default && CompilationType != AOTCompilationType.None; + public bool IsHybridAOT => IsAOT && Kind == AOTKind.Hybrid; + + public AOTCompilationType CompilationType { get; private set; } = AOTCompilationType.Default; + public AOTKind Kind { get; private set; } = AOTKind.Standard; + + public List IncludedAssemblies { get; private set; } = new List (); + public List ExcludedAssemblies { get; private set; } = new List (); + + public AOTOptions (string options) + { + // Syntax - all,core,sdk,none or "" if explicit then optional list of +/-'ed assemblies + // Sections seperated by , + string [] optionParts = options.Split (','); + for (int i = 0 ; i < optionParts.Length ; ++i) { + string option = optionParts [i]; + + AOTKind kind = AOTKind.Default; + // Technically '|' is valid in a file name, so |hybrid.dll would be as well. + // So check the left hand side for a valid option and pass if not + if (option.Contains ("|")) { + string [] optionTypeParts = option.Split ('|'); + if (optionTypeParts.Length != 2) + throw new MonoMacException (20, true, "The valid options for '{0}' are '{1}'.", "--aot", "{none, all, core, sdk}{|hybrid}, then an optional explicit list of assemblies."); + switch (optionTypeParts [0]) { + case "none": + case "core": + case "sdk": + case "all": { + option = optionTypeParts [0]; + switch (optionTypeParts [1]) { + case "hybrid": + kind = AOTKind.Hybrid; + break; + case "standard": + kind = AOTKind.Standard; + break; + default: + throw new MonoMacException (20, true, "The valid options for '{0}' are '{1}'.", "--aot", "{none, all, core, sdk}{|hybrid}, then an optional explicit list of assemblies."); + } + break; + } + default: + break; + } + } + + switch (option) { + case "none": + CompilationType = AOTCompilationType.None; + if (kind != AOTKind.Default) + Kind = kind; + continue; + case "all": + CompilationType = AOTCompilationType.All; + if (kind != AOTKind.Default) + Kind = kind; + continue; + case "sdk": + CompilationType = AOTCompilationType.SDK; + if (kind != AOTKind.Default) + Kind = kind; + continue; + case "core": + CompilationType = AOTCompilationType.Core; + if (kind != AOTKind.Default) + Kind = kind; + continue; + } + + if (option.StartsWith ("+", StringComparison.Ordinal)) { + if (CompilationType == AOTCompilationType.Default) + CompilationType = AOTCompilationType.Explicit; + IncludedAssemblies.Add (option.Substring (1)); + continue; + } + if (option.StartsWith ("-", StringComparison.Ordinal)) { + if (CompilationType == AOTCompilationType.Default) + CompilationType = AOTCompilationType.Explicit; + ExcludedAssemblies.Add (option.Substring (1)); + continue; + } + throw new MonoMacException (20, true, "The valid options for '{0}' are '{1}'.", "--aot", "{none, all, core, sdk}{|hybrid}, then an optional explicit list of assemblies."); + } + if (CompilationType == AOTCompilationType.Default) + throw new MonoMacException (20, true, "The valid options for '{0}' are '{1}'.", "--aot", "{none, all, core, sdk}{|hybrid}, then an optional explicit list of assemblies."); + + } + } + public class AOTCompiler { - enum AotType { - Default, - None, - All, - Core, - SDK, - Explicit - } - - AotType aotType = AotType.Default; - public bool IsAOT => aotType != AotType.Default && aotType != AotType.None; - - // Set to Key -> True when we've seen a given include/exclude during compile to catch errors - Dictionary includedAssemblies = new Dictionary (); - Dictionary excludedAssemblies = new Dictionary (); - // Allows tests to stub out actual compilation and parallelism public RunCommandDelegate RunCommand { get; set; } = Driver.RunCommand; public ParallelOptions ParallelOptions { get; set; } = new ParallelOptions () { MaxDegreeOfParallelism = Driver.Concurrency }; @@ -89,47 +180,46 @@ namespace Xamarin.Bundler { public string Quote (string f) => Driver.Quote (f); - public void Parse (string options) - { - // Syntax - all,core,sdk,none or "" if explicit then optional list of +/-'ed assemblies - // Sections seperated by , - foreach (var option in options.Split (',')) { - switch (option) { - case "none": - aotType = AotType.None; - continue; - case "all": - aotType = AotType.All; - continue; - case "sdk": - aotType = AotType.SDK; - continue; - case "core": - aotType = AotType.Core; - continue; - } + AOTOptions options; + AOTCompilerType compilerType; - if (option.StartsWith ("+", StringComparison.Ordinal)) { - if (aotType == AotType.Default) - aotType = AotType.Explicit; - includedAssemblies.Add (option.Substring (1), false); - continue; - } - if (option.StartsWith ("-", StringComparison.Ordinal)) { - if (aotType == AotType.Default) - aotType = AotType.Explicit; - excludedAssemblies.Add (option.Substring (1), false); - continue; - } - throw new MonoMacException (20, true, "The valid options for '{0}' are '{1}'.", "--aot", "none, all, core, sdk, and an explicit list of assemblies."); - } - if (aotType == AotType.Default) - throw new MonoMacException (20, true, "The valid options for '{0}' are '{1}'.", "--aot", "none, all, core, sdk, and an explicit list of assemblies."); + public AOTCompiler (AOTOptions options, AOTCompilerType compilerType) + { + this.options = options; + this.compilerType = compilerType; + } + + public void Compile (string path) + { + Compile (new FileSystemEnumerator (path)); + } + + public void Compile (IFileEnumerator files) + { + if (!options.IsAOT) + throw ErrorHelper.CreateError (0099, "Internal error \"AOTBundle with aot: {0}\" Please file a bug report with a test case (http://bugzilla.xamarin.com).", options.CompilationType); + + var monoEnv = new string [] {"MONO_PATH", files.RootDir }; + + Parallel.ForEach (GetFilesToAOT (files), ParallelOptions, file => { + if (RunCommand (MonoPath, String.Format ("--aot{0} {1}", options.IsHybridAOT ? "=hybrid" : "", Quote (file)), monoEnv) != 0) + throw ErrorHelper.CreateError (3001, "Could not AOT the assembly '{0}'", file); + }); } List GetFilesToAOT (IFileEnumerator files) { + // Make a dictionary of included/excluded files to track if we've missed some at the end + Dictionary includedAssemblies = new Dictionary (); + foreach (var item in options.IncludedAssemblies) + includedAssemblies [item] = false; + + Dictionary excludedAssemblies = new Dictionary (); + foreach (var item in options.ExcludedAssemblies) + excludedAssemblies [item] = false; + var aotFiles = new List (); + foreach (var file in files.Files) { string fileName = Path.GetFileName (file); string extension = Path.GetExtension (file); @@ -137,33 +227,33 @@ namespace Xamarin.Bundler { continue; if (excludedAssemblies.ContainsKey (fileName)) { - excludedAssemblies[fileName] = true; + excludedAssemblies [fileName] = true; continue; } if (includedAssemblies.ContainsKey (fileName)) { - includedAssemblies[fileName] = true; + includedAssemblies [fileName] = true; aotFiles.Add (file); continue; } - switch (aotType) { - case AotType.All: + switch (options.CompilationType) { + case AOTCompilationType.All: aotFiles.Add (file); break; - case AotType.SDK: + case AOTCompilationType.SDK: string fileNameNoExtension = Path.GetFileNameWithoutExtension (fileName); if (Profile.IsSdkAssembly (fileNameNoExtension) || fileName == "Xamarin.Mac.dll") aotFiles.Add (file); break; - case AotType.Core: + case AOTCompilationType.Core: if (fileName == "Xamarin.Mac.dll" || fileName == "System.dll" || fileName == "mscorlib.dll") aotFiles.Add (file); break; - case AotType.Explicit: + case AOTCompilationType.Explicit: break; // In explicit, only included includedAssemblies included default: - throw ErrorHelper.CreateError (0099, "Internal error \"GetFilesToAOT with aot: {0}\" Please file a bug report with a test case (http://bugzilla.xamarin.com).", aotType); + throw ErrorHelper.CreateError (0099, "Internal error \"GetFilesToAOT with aot: {0}\" Please file a bug report with a test case (http://bugzilla.xamarin.com).", options.CompilationType); } } @@ -178,38 +268,22 @@ namespace Xamarin.Bundler { return aotFiles; } - string GetMonoPath (MonoType monoType) + string MonoPath { - switch (monoType) { - case MonoType.Bundled64: - return Path.Combine (XamarinMacPrefix, "bin/bmac-mobile-mono"); - case MonoType.Bundled32: - return Path.Combine (XamarinMacPrefix, "bin/bmac-mobile-mono-32"); - case MonoType.System64: - return "/Library/Frameworks/Mono.framework/Commands/mono64"; - case MonoType.System32: - return "/Library/Frameworks/Mono.framework/Commands/mono32"; - default: - throw ErrorHelper.CreateError (0099, "Internal error \"GetMonoPath with monoType: {0}\" Please file a bug report with a test case (http://bugzilla.xamarin.com).", monoType); + get { + switch (compilerType) { + case AOTCompilerType.Bundled64: + return Path.Combine (XamarinMacPrefix, "bin/bmac-mobile-mono"); + case AOTCompilerType.Bundled32: + return Path.Combine (XamarinMacPrefix, "bin/bmac-mobile-mono-32"); + case AOTCompilerType.System64: + return "/Library/Frameworks/Mono.framework/Commands/mono64"; + case AOTCompilerType.System32: + return "/Library/Frameworks/Mono.framework/Commands/mono32"; + default: + throw ErrorHelper.CreateError (0099, "Internal error \"MonoPath with compilerType: {0}\" Please file a bug report with a test case (http://bugzilla.xamarin.com).", compilerType); + } } } - - public void Compile (MonoType monoType, string path) - { - Compile (monoType, new FileSystemEnumerator (path)); - } - - public void Compile (MonoType monoType, IFileEnumerator files) - { - if (!IsAOT) - throw ErrorHelper.CreateError (0099, "Internal error \"AOTBundle with aot: {0}\" Please file a bug report with a test case (http://bugzilla.xamarin.com).", aotType); - - var monoEnv = new string [] {"MONO_PATH", files.RootDir }; - - Parallel.ForEach (GetFilesToAOT (files), ParallelOptions, file => { - if (RunCommand (GetMonoPath (monoType), String.Format ("--aot=hybrid {0}", Quote (file)), monoEnv) != 0) - throw ErrorHelper.CreateError (3001, "Could not AOT the assembly '{0}'", file); - }); - } } } diff --git a/tools/mmp/driver.cs b/tools/mmp/driver.cs index 38dc9c3a4b..36f8c9027f 100644 --- a/tools/mmp/driver.cs +++ b/tools/mmp/driver.cs @@ -187,7 +187,7 @@ namespace Xamarin.Bundler { static int watch_level; static Stopwatch watch; - static AOTCompiler aot = new AOTCompiler (); + static AOTOptions aotOptions = null; static string xm_framework_dir; public static string MMPDirectory { @@ -362,7 +362,7 @@ namespace Xamarin.Bundler { { "xamarin-system-framework", "Used with --target-framework=4.5 to select XM 4.5 Target Framework", v => { IsUnifiedFullSystemFramework = true; } }, { "aot:", "Specify assemblies that should be compiled via experimental AOT.\n- none - No AOT (default)\n- all - Every assembly in MonoBundle not ignored\n- core - Just Xamarin.Mac.dll, System.dll, and mscorlib.dll\n sdk - Xamarin.Mac.dll and all BCL assemblies\nIndividual files can be included for AOT via +FileName.dll and excluded via -FileName.dll", v => { - aot.Parse (v); + aotOptions = new AOTOptions (v); } }, }; @@ -380,6 +380,12 @@ namespace Xamarin.Bundler { throw new MonoMacException (10, true, "Could not parse the command line arguments: {0}", e.Message); } + if (aotOptions == null) { + string forceAotVariable = Environment.GetEnvironmentVariable ("XM_FORCE_AOT"); + if (forceAotVariable != null) + aotOptions = new AOTOptions (forceAotVariable); + } + App.RuntimeOptions = RuntimeOptions.Create (App, http_message_provider, tls_provider); ErrorHelper.Verbosity = verbose; @@ -808,19 +814,19 @@ namespace Xamarin.Bundler { if (App.LinkMode != LinkMode.All && App.RuntimeOptions != null) App.RuntimeOptions.Write (App.AppDirectory); - if (aot.IsAOT) { + if (aotOptions != null && aotOptions.IsAOT) { if (!IsUnified) throw new MonoMacException (98, true, "AOT compilation is only available on Unified"); - MonoType monoType; + AOTCompilerType compilerType; if (IsUnifiedMobile || IsUnifiedFullXamMacFramework) - monoType = Is64Bit ? MonoType.Bundled64 : MonoType.Bundled32; + compilerType = Is64Bit ? AOTCompilerType.Bundled64 : AOTCompilerType.Bundled32; else if (IsUnifiedFullSystemFramework) - monoType = Is64Bit ? MonoType.System64 : MonoType.System32; + compilerType = Is64Bit ? AOTCompilerType.System64 : AOTCompilerType.System32; else throw ErrorHelper.CreateError (0099, "Internal error \"AOT with unexpected profile.\" Please file a bug report with a test case (http://bugzilla.xamarin.com)."); - - aot.Compile (monoType, mmp_dir); + AOTCompiler compiler = new AOTCompiler (aotOptions, compilerType); + compiler.Compile (mmp_dir); Watch ("AOT Compile", 1); } @@ -1085,8 +1091,8 @@ namespace Xamarin.Bundler { else sw.WriteLine ("\tsetenv (\"MONO_GC_PARAMS\", \"major=marksweep\", 1);"); - if (aot.IsAOT) - sw.WriteLine ("\txamarin_mac_aot = TRUE;"); + if (aotOptions != null && aotOptions.IsHybridAOT) + sw.WriteLine ("\txamarin_mac_hybrid_aot = TRUE;"); sw.WriteLine ("\treturn 0;"); sw.WriteLine ("}"); diff --git a/tools/mmp/tests/aot.cs b/tools/mmp/tests/aot.cs index 4b45c9cb19..a8df6e105e 100644 --- a/tools/mmp/tests/aot.cs +++ b/tools/mmp/tests/aot.cs @@ -25,20 +25,24 @@ namespace Xamarin.MMP.Tests.Unit } } - AOTCompiler compiler; List> commandsRun; [SetUp] public void Init () { - compiler = new AOTCompiler () + // Make sure this is cleared between every test + commandsRun = new List> (); + } + + void Compile (AOTOptions options, TestFileEnumerator files, AOTCompilerType compilerType = AOTCompilerType.Bundled64, RunCommandDelegate onRunDelegate = null) + { + AOTCompiler compiler = new AOTCompiler (options, compilerType) { - RunCommand = OnRunCommand, + RunCommand = onRunDelegate != null ? onRunDelegate : OnRunCommand, ParallelOptions = new ParallelOptions () { MaxDegreeOfParallelism = 1 }, XamarinMacPrefix = Driver.WalkUpDirHierarchyLookingForLocalBuild (), // HACK - AOT test shouldn't need this from driver.cs }; - - commandsRun = new List> (); + compiler.Compile (files); } void ClearCommandsRun () @@ -54,16 +58,16 @@ namespace Xamarin.MMP.Tests.Unit return 0; } - string GetExpectedMonoCommand (MonoType monoType) + string GetExpectedMonoCommand (AOTCompilerType compilerType) { - switch (monoType) { - case MonoType.Bundled64: + switch (compilerType) { + case AOTCompilerType.Bundled64: return "bmac-mobile-mono"; - case MonoType.Bundled32: + case AOTCompilerType.Bundled32: return "bmac-mobile-mono-32"; - case MonoType.System64: + case AOTCompilerType.System64: return "mono64"; - case MonoType.System32: + case AOTCompilerType.System32: return "mono32"; default: Assert.Fail ("GetMonoPath with invalid option"); @@ -71,22 +75,26 @@ namespace Xamarin.MMP.Tests.Unit } } - List GetFiledAOTed (MonoType monoType = MonoType.Bundled64) + List GetFiledAOTed (AOTCompilerType compilerType = AOTCompilerType.Bundled64, AOTKind kind = AOTKind.Standard) { List filesAOTed = new List (); foreach (var command in commandsRun) { - Assert.IsTrue (command.Item1.EndsWith (GetExpectedMonoCommand (monoType)), "Unexpected command: " + command.Item1); - Assert.AreEqual (command.Item2.Split (' ')[0], "--aot=hybrid", "First arg should be --aot=hybrid"); + Assert.IsTrue (command.Item1.EndsWith (GetExpectedMonoCommand (compilerType)), "Unexpected command: " + command.Item1); + if (kind == AOTKind.Hybrid) + Assert.AreEqual (command.Item2.Split (' ')[0], "--aot=hybrid", "First arg should be --aot=hybrid"); + else + Assert.AreEqual (command.Item2.Split (' ')[0], "--aot", "First arg should be --aot"); + string fileName = command.Item2.Substring (command.Item2.IndexOf(' ') + 1).Replace ("\"", ""); filesAOTed.Add (fileName); } return filesAOTed; } - void AssertFilesAOTed (IEnumerable expectedFiles, MonoType monoType = MonoType.Bundled64) + void AssertFilesAOTed (IEnumerable expectedFiles, AOTCompilerType compilerType = AOTCompilerType.Bundled64, AOTKind kind = AOTKind.Standard) { - List filesAOTed = GetFiledAOTed (monoType); + List filesAOTed = GetFiledAOTed (compilerType, kind); Func getErrorDetails = () => $"\n {String.Join (" ", filesAOTed)} \nvs\n {String.Join (" ", expectedFiles)}"; @@ -123,18 +131,18 @@ namespace Xamarin.MMP.Tests.Unit [Test] public void ParsingNone_DoesNoAOT () { - compiler.Parse ("none"); - Assert.IsFalse (compiler.IsAOT, "Parsing none should not be IsAOT"); - AssertThrowErrorWithCode (() => compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)), 99); + var options = new AOTOptions ("none"); + Assert.IsFalse (options.IsAOT, "Parsing none should not be IsAOT"); + AssertThrowErrorWithCode (() => Compile (options, new TestFileEnumerator (FullAppFileList)), 99); } [Test] public void All_AOTAllFiles () { - compiler.Parse ("all"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("all"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)); + Compile (options, new TestFileEnumerator (FullAppFileList)); var expectedFiles = FullAppFileList.Where (x => x.EndsWith (".exe") || x.EndsWith (".dll")); AssertFilesAOTed (expectedFiles); @@ -143,10 +151,10 @@ namespace Xamarin.MMP.Tests.Unit [Test] public void Core_ParsingJustCoreFiles() { - compiler.Parse ("core"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("core"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)); + Compile (options, new TestFileEnumerator (FullAppFileList)); AssertFilesAOTed (CoreXMFileList); } @@ -154,22 +162,21 @@ namespace Xamarin.MMP.Tests.Unit [Test] public void SDK_ParsingJustSDKFiles() { - compiler.Parse ("sdk"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("sdk"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)); + Compile (options, new TestFileEnumerator (FullAppFileList)); AssertFilesAOTed (SDKFileList); } - [Test] public void ExplicitAssembly_JustAOTExplicitFile () { - compiler.Parse ("+System.dll"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("+System.dll"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)); + Compile (options, new TestFileEnumerator (FullAppFileList)); AssertFilesAOTed (new string [] { "System.dll" }); } @@ -177,13 +184,13 @@ namespace Xamarin.MMP.Tests.Unit [Test] public void CoreWithInclusionAndSubtraction () { - compiler.Parse ("core,+Foo.dll,-Xamarin.Mac.dll"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("core,+Foo.dll,-Xamarin.Mac.dll"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); string [] testFiles = { "Foo.dll", "Foo Bar.exe", "libMonoPosixHelper.dylib", "mscorlib.dll", "Xamarin.Mac.dll", "System.dll" }; - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (testFiles)); + Compile (options, new TestFileEnumerator (testFiles)); AssertFilesAOTed (new string [] { "Foo.dll", "mscorlib.dll", "System.dll" }); } @@ -191,54 +198,55 @@ namespace Xamarin.MMP.Tests.Unit [Test] public void CoreWithFullPath_GivesFullPathCommands () { - compiler.Parse ("core,-Xamarin.Mac.dll"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("core,-Xamarin.Mac.dll"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); + + Compile (options, new TestFileEnumerator (FullAppFileList.Select (x => TestRootDir + x))); - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList.Select (x => TestRootDir + x))); AssertFilesAOTed (new string [] { TestRootDir + "mscorlib.dll", TestRootDir + "System.dll" }); } [Test] public void ExplicitNegativeFileWithNonExistantFiles_ThrowError () { - compiler.Parse ("core,-NonExistant.dll"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("core,-NonExistant.dll"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - AssertThrowErrorWithCode (() => compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)), 3010); + AssertThrowErrorWithCode (() => Compile (options, new TestFileEnumerator (FullAppFileList)), 3010); } [Test] public void ExplicitPositiveFileWithNonExistantFiles_ThrowError () { - compiler.Parse ("core,+NonExistant.dll"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("core,+NonExistant.dll"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - AssertThrowErrorWithCode (() => compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)), 3009); + AssertThrowErrorWithCode (() => Compile (options, new TestFileEnumerator (FullAppFileList)), 3009); } [Test] public void ExplicitNegativeWithNoAssemblies_ShouldNoOp() { - compiler.Parse ("-System.dll"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("-System.dll"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)); + Compile (options, new TestFileEnumerator (FullAppFileList)); AssertFilesAOTed (new string [] {}); } [Test] public void ParsingSimpleOptions_InvalidOption () { - AssertThrowErrorWithCode (() => compiler.Parse ("FooBar"), 20); + AssertThrowErrorWithCode (() => new AOTOptions ("FooBar"), 20); } [Test] public void AssemblyWithSpaces_ShouldAOTWithQuotes () { - compiler.Parse ("+Foo Bar.dll"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("+Foo Bar.dll"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (new string [] { "Foo Bar.dll", "Xamarin.Mac.dll" })); + Compile (options, new TestFileEnumerator (new string [] { "Foo Bar.dll", "Xamarin.Mac.dll" })); AssertFilesAOTed (new string [] {"Foo Bar.dll"}); Assert.IsTrue (commandsRun[0].Item2.EndsWith ("\"Foo Bar.dll\"", StringComparison.InvariantCulture), "Should end with quoted filename"); } @@ -246,25 +254,62 @@ namespace Xamarin.MMP.Tests.Unit [Test] public void WhenAOTFails_ShouldReturnError () { - compiler.RunCommand = (path, args, env, output, suppressPrintOnErrors) => 42; - compiler.Parse ("all"); - AssertThrowErrorWithCode (() => compiler.Compile (MonoType.Bundled64, new TestFileEnumerator (FullAppFileList)), 3001); + RunCommandDelegate runThatErrors = (path, args, env, output, suppressPrintOnErrors) => 42; + var options = new AOTOptions ("all"); + + AssertThrowErrorWithCode (() => Compile (options, new TestFileEnumerator (FullAppFileList), onRunDelegate : runThatErrors), 3001); } [Test] public void DifferentMonoTypes_ShouldInvokeCorrectMono () { - foreach (var monoType in new List (){ MonoType.Bundled64, MonoType.Bundled32, MonoType.System32, MonoType.System64 }) + foreach (var compilerType in new List (){ AOTCompilerType.Bundled64, AOTCompilerType.Bundled32, AOTCompilerType.System32, AOTCompilerType.System64 }) { ClearCommandsRun (); - compiler.Parse ("sdk"); - Assert.IsTrue (compiler.IsAOT, "Should be IsAOT"); + var options = new AOTOptions ("sdk"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); - compiler.Compile (monoType, new TestFileEnumerator (FullAppFileList)); + Compile (options, new TestFileEnumerator (FullAppFileList), compilerType); - AssertFilesAOTed (SDKFileList, monoType); + AssertFilesAOTed (SDKFileList, compilerType); } } + [Test] + public void PipeFileName_ShouldNotHybridCompiler () + { + foreach (var testCase in new string [] { "+|hybrid.dll", "core,+|hybrid.dll,-Xamarin.Mac.dll" }){ + ClearCommandsRun (); + var options = new AOTOptions (testCase); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); + Assert.IsFalse (options.IsHybridAOT, "Should not be IsHybridAOT"); + + Compile (options, new TestFileEnumerator (new string [] { "|hybrid.dll", "Xamarin.Mac.dll" })); + AssertFilesAOTed (new string [] {"|hybrid.dll"}); + } + } + + [Test] + public void InvalidHybridOptions_ShouldThrow () + { + AssertThrowErrorWithCode (() => new AOTOptions ("|"), 20); + AssertThrowErrorWithCode (() => new AOTOptions ("|hybrid"), 20); + AssertThrowErrorWithCode (() => new AOTOptions ("core|"), 20); + AssertThrowErrorWithCode (() => new AOTOptions ("foo|hybrid"), 20); + AssertThrowErrorWithCode (() => new AOTOptions ("core|foo"), 20); + AssertThrowErrorWithCode (() => new AOTOptions ("|hybrid,+Foo.dll"), 20); + } + + [Test] + public void HybridOption_ShouldInvokeHybridCompiler () + { + var options = new AOTOptions ("sdk|hybrid"); + Assert.IsTrue (options.IsAOT, "Should be IsAOT"); + Assert.IsTrue (options.IsHybridAOT, "Should be IsHybridAOT"); + + Compile (options, new TestFileEnumerator (FullAppFileList)); + + AssertFilesAOTed (SDKFileList, kind : AOTKind.Hybrid); + } } }