using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace xharness { public static class MakefileGenerator { static void WriteTarget (this StreamWriter writer, string target, string dependencies, params string [] arguments) { var t = string.Format (target, arguments); if (t.Contains ("\\ ")) { writer.Write (t.Replace ("\\ ", ""), arguments); writer.Write (" "); } writer.Write (t); if (!string.IsNullOrEmpty (dependencies)) { writer.Write (": "); writer.WriteLine (dependencies, arguments); } else { writer.WriteLine (":"); } } enum MacTargetNameType { Build, Clean, Exec, Run } static string MakeMacTargetName (MacTarget target, MacTargetNameType type) { if (target is MacClassicTarget) return MakeMacClassicTargetName (target, type); else if (target is MacUnifiedTarget) return MakeMacUnifiedTargetName (target, type); else throw new NotImplementedException (); } static string MakeMacClassicTargetName (MacTarget target, MacTargetNameType type) { var make_escaped_suffix = "-" + target.Platform.Replace (" ", "\\ "); var make_escaped_name = target.SimplifiedName.Replace (" ", "\\ "); switch (type) { case MacTargetNameType.Build: return string.Format ("build{0}-classic-{1}", make_escaped_suffix, make_escaped_name); case MacTargetNameType.Clean: return string.Format ("clean{0}-classic-{1}", make_escaped_suffix, make_escaped_name); case MacTargetNameType.Exec: return string.Format ("exec{0}-classic-{1}", make_escaped_suffix, make_escaped_name); case MacTargetNameType.Run: return string.Format ("run{0}-classic-{1}", make_escaped_suffix, make_escaped_name); default: throw new NotImplementedException (); } } static string MakeMacUnifiedTargetName (MacTarget target, MacTargetNameType type) { var make_escaped_suffix = "-" + target.Platform.Replace (" ", "\\ "); var make_escaped_name = target.SimplifiedName.Replace (" ", "\\ "); switch (type) { case MacTargetNameType.Build: return string.Format ("build{0}-{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); case MacTargetNameType.Clean: return string.Format ("clean{0}-{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); case MacTargetNameType.Exec: return string.Format ("exec{0}-{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); case MacTargetNameType.Run: return string.Format ("run{0}-{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); default: throw new NotImplementedException (); } } static string CreateRelativePath (string path, string relative_to) { if (path.StartsWith (relative_to, StringComparison.Ordinal)) { var rv = path.Substring (relative_to.Length); if (relative_to [relative_to.Length - 1] != Path.PathSeparator) rv = rv.Substring (1); return rv; } return path; } public static void CreateMacMakefile (Harness harness, IEnumerable targets) { var makefile = Path.Combine (harness.RootDirectory, "Makefile-mac.inc"); using (var writer = new StreamWriter (makefile, false, new UTF8Encoding (false))) { writer.WriteLine (".stamp-configure-projects-mac: Makefile xharness/xharness.exe"); writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug xharness/xharness.exe $(XHARNESS_VERBOSITY) --configure --autoconf --rootdir $(CURDIR)"); writer.WriteLine ("\t$(Q) touch $@"); writer.WriteLine (); var allTargets = new List (); allTargets.AddRange (targets); List allTargetNames = new List (allTargets.Count); List allTargetCleanNames = new List (allTargets.Count); // build/[install/]run targets for specific test projects. foreach (var target in allTargets) { var make_escaped_simplified_name = target.SimplifiedName.Replace (" ", "\\ "); var make_escaped_name = target.Name.Replace (" ", "\\ "); writer.WriteLine (); if (target.ProjectPath != target.TemplateProjectPath) { writer.WriteLine ("# {0} for {1}", make_escaped_simplified_name, target.Suffix.Replace ("-", "")); writer.WriteLine (".stamp-configure-projects-mac: {0}", target.TemplateProjectPath.Replace (" ", "\\ ")); writer.WriteLine ("{0}: .stamp-configure-projects-mac", target.ProjectPath.Replace (" ", "\\ ")); writer.WriteLine (); } // build project target if (target.IsBCLProject) { throw new NotImplementedException (); } else if (target is MacClassicTarget) { allTargetNames.Add (MakeMacClassicTargetName (target, MacTargetNameType.Build)); allTargetCleanNames.Add (MakeMacClassicTargetName (target, MacTargetNameType.Clean)); // mdtool can only find referenced projects if the referenced // projects are included in the solution. This requires us to // build the solution (if it exists), not the project. var slnPath = Path.ChangeExtension (target.ProjectPath, "sln"); var fileToBuild = File.Exists (slnPath) ? slnPath : target.ProjectPath; writer.WriteTarget (MakeMacClassicTargetName (target, MacTargetNameType.Build), "$(GUI_UNIT_PATH)/bin/net_4_5/GuiUnit.exe"); writer.WriteLine ("\t$(Q) $(MDTOOL) build {0}", fileToBuild); writer.WriteLine (); writer.WriteTarget (MakeMacClassicTargetName (target, MacTargetNameType.Clean), ""); writer.WriteLine ("\t$(Q) $(MDTOOL) build -t:Clean {0}", fileToBuild); writer.WriteLine (); writer.WriteTarget (MakeMacClassicTargetName (target, MacTargetNameType.Exec), ""); writer.WriteLine ("\t$(Q) {0}/bin/x86/Debug/{1}.app/Contents/MacOS/{1}", CreateRelativePath (Path.GetDirectoryName (target.ProjectPath), Path.GetDirectoryName (makefile)), make_escaped_name); writer.WriteLine (); writer.WriteTarget (MakeMacClassicTargetName (target, MacTargetNameType.Run), ""); writer.WriteLine ("\t$(Q) $(MAKE) {0}", MakeMacClassicTargetName (target, MacTargetNameType.Build)); writer.WriteLine ("\t$(Q) $(MAKE) {0}", MakeMacClassicTargetName (target, MacTargetNameType.Exec)); writer.WriteLine (); } else { allTargetNames.Add (MakeMacUnifiedTargetName (target, MacTargetNameType.Build)); allTargetCleanNames.Add (MakeMacUnifiedTargetName (target, MacTargetNameType.Clean)); string guiUnitDependency = ((MacUnifiedTarget)target).Mobile ? "$(GUI_UNIT_PATH)/bin/xammac_mobile/GuiUnit.exe" : "$(GUI_UNIT_PATH)/bin/net_4_5/GuiUnit.exe"; writer.WriteTarget (MakeMacUnifiedTargetName (target, MacTargetNameType.Build), "{0}", target.ProjectPath.Replace (" ", "\\ ") + " " + guiUnitDependency); writer.WriteLine ("\t$(Q_XBUILD) $(SYSTEM_XBUILD) \"/property:Configuration=$(CONFIG)\" /t:Build $(XBUILD_VERBOSITY) \"{0}\"", target.ProjectPath); writer.WriteLine (); writer.WriteTarget (MakeMacUnifiedTargetName (target, MacTargetNameType.Clean), ""); writer.WriteLine ("\t$(Q_XBUILD) $(SYSTEM_XBUILD) \"/property:Configuration=$(CONFIG)\" /t:Clean $(XBUILD_VERBOSITY) \"{0}\"", target.ProjectPath); writer.WriteLine (); writer.WriteTarget (MakeMacUnifiedTargetName (target, MacTargetNameType.Exec), ""); writer.WriteLine ("\t$(Q) {2}/bin/x86/Debug{1}/{0}.app/Contents/MacOS/{0}", make_escaped_name, target.Suffix, CreateRelativePath (Path.GetDirectoryName (target.ProjectPath), Path.GetDirectoryName (makefile))); writer.WriteLine (); writer.WriteTarget (MakeMacUnifiedTargetName (target, MacTargetNameType.Run), ""); writer.WriteLine ("\t$(Q) $(MAKE) {0}", MakeMacUnifiedTargetName (target, MacTargetNameType.Build)); writer.WriteLine ("\t$(Q) $(MAKE) {0}", MakeMacUnifiedTargetName (target, MacTargetNameType.Exec)); writer.WriteLine (); } writer.WriteLine (); } writer.WriteLine ("# Env Variables to use local not system XM"); writer.WriteLine (); var enviromentalVariables = new Dictionary () { { "XBUILD_FRAMEWORK_FOLDERS_PATH", "$(MAC_DESTDIR)/Library/Frameworks/Mono.framework/External/xbuild-frameworks"}, { "MSBuildExtensionsPath", "$(MAC_DESTDIR)/Library/Frameworks/Mono.framework/External/xbuild"}, { "MD_APPLE_SDK_ROOT", "$(shell dirname `dirname $(XCODE_DEVELOPER_ROOT)`)"} }; foreach (var key in enviromentalVariables) { writer.WriteLine ("{0}: export {1}:={2}", string.Join (" ", allTargetNames.ToArray ()), key.Key, key.Value); writer.WriteLine ("{0}: export {1}:={2}", string.Join (" ", allTargetCleanNames.ToArray ()), key.Key, key.Value); } writer.WriteLine ("# Container targets that run multiple test projects"); writer.WriteLine (); var grouped = allTargets.GroupBy ((target) => target.SimplifiedName); foreach (MacTargetNameType action in Enum.GetValues (typeof (MacTargetNameType))) { var actionName = action.ToString ().ToLowerInvariant (); foreach (var group in grouped) { var targetName = group.Key; writer.WriteLine ("{0}-mac-{1}:", actionName, targetName); writer.WriteLine ("\t$(Q) rm -f \".$@-failure.stamp\""); foreach (var entry in group) writer.WriteLine ("\t$(Q) $(MAKE) {0} || echo \"{0} failed\" >> \".$@-failure.stamp\"", MakeMacTargetName (entry, action)); writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); } } writer.WriteLine ("mac-run run-mac:"); writer.WriteLine ("\t$(Q) rm -rf \".$@-failure.stamp\""); foreach (var target in allTargets) { if (target is MacClassicTarget) writer.WriteLine ("\t$(Q) $(MAKE) \"{0}\" || echo \"{0} failed\" >> \".$@-failure.stamp\"", MakeMacClassicTargetName (target, MacTargetNameType.Run)); else if (target is MacUnifiedTarget) writer.WriteLine ("\t$(Q) $(MAKE) \"{0}\" || echo \"{0} failed\" >> \".$@-failure.stamp\"", MakeMacUnifiedTargetName (target, MacTargetNameType.Run)); else throw new NotImplementedException (); } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); writer.WriteLine ("mac-build mac-build-all build-mac:"); // build everything writer.WriteLine ("\t$(Q) rm -rf \".$@-failure.stamp\""); foreach (var target in allTargets) { if (target is MacClassicTarget) writer.WriteLine ("\t$(Q) $(MAKE) \"{0}\" || echo \"{0} failed\" >> \".$@-failure.stamp\"", MakeMacClassicTargetName (target, MacTargetNameType.Build)); else if (target is MacUnifiedTarget) writer.WriteLine ("\t$(Q) $(MAKE) \"{0}\" || echo \"{0} failed\" >> \".$@-failure.stamp\"", MakeMacUnifiedTargetName (target, MacTargetNameType.Build)); else throw new NotImplementedException (); } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); } } static void WriteCollectionTarget (StreamWriter writer, string target, IEnumerable targets, string mode) { writer.WriteLine (); writer.Write (target); writer.WriteLine (":"); foreach (var t in targets.Where ((v) => v.IsExe)) { if (t is ClassicTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-{2}compat-{1}\" || echo \"run{0}-{2}compat-{1} failed\" >> \".$@-failure.stamp\"", "-ios", t.Name, mode); } else if (t is UnifiedTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-{2}unified-{1}\" || echo \"run{0}-{2}unified-{1} failed\" >> \".$@-failure.stamp\"", "-ios", t.Name, mode); } else { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-{2}-{1}\" || echo \"run{0}-{2}-{1} failed\" >> \".$@-failure.stamp\"", t.Suffix, t.Name, mode); } } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); } public static void CreateMakefile (Harness harness, IEnumerable classic_targets, IEnumerable unified_targets, IEnumerable tvos_targets, IEnumerable watchos_targets) { var makefile = Path.Combine (harness.RootDirectory, "Makefile.inc"); using (var writer = new StreamWriter (makefile, false, new UTF8Encoding (false))) { writer.WriteLine (".stamp-configure-projects: Makefile xharness/xharness.exe"); writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug xharness/xharness.exe $(XHARNESS_VERBOSITY) --configure --autoconf --rootdir $(CURDIR)"); writer.WriteLine ("\t$(Q) touch $@"); writer.WriteLine (); var allTargets = new List (); allTargets.AddRange (classic_targets); allTargets.AddRange (unified_targets); allTargets.AddRange (tvos_targets); allTargets.AddRange (watchos_targets); // build/[install/]run targets for specific test projects. foreach (var target in allTargets) { if (!target.IsExe) continue; var make_escaped_suffix = "-" + target.Platform.Replace (" ", "\\ "); var make_escaped_name = target.Name.Replace (" ", "\\ "); writer.WriteLine (); if (target.ProjectPath != target.TemplateProjectPath) { writer.WriteLine ("# {0} for {1}", target.Name, target.Suffix.Replace ("-", "")); writer.WriteLine (".stamp-configure-projects: {0}", target.TemplateProjectPath.Replace (" ", "\\ ")); writer.WriteLine ("{0}: .stamp-configure-projects", target.ProjectPath.Replace (" ", "\\ "), target.TemplateProjectPath.Replace (" ", "\\ ")); writer.WriteLine (); } // build sim project target if (target.IsBCLProject) { writer.WriteTarget ("build{0}-bcl-sim{2}-{1}", "build{0}-sim{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Build succeeded"); // This is important, otherwise we'll end up executing the catch-all build-% target writer.WriteLine (); } writer.WriteTarget ("build{0}-sim{3}-{1}", "{2}", make_escaped_suffix, make_escaped_name, target.ProjectPath.Replace (" ", "\\ "), target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q_XBUILD) $(SYSTEM_XBUILD) \"/property:Configuration=$(CONFIG)\" \"/property:Platform=iPhoneSimulator\" /t:Build $(XBUILD_VERBOSITY) \"{0}\"", target.ProjectPath); writer.WriteLine (); if (target is ClassicTarget) { // target that builds both Classic+Unified writer.WriteTarget ("build{0}-sim-{1}", "build{0}-simclassic-{1} build{0}-simunified-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Build succeeded"); // This is important, otherwise we'll end up executing the catch-all build-% target writer.WriteLine (); } // clean sim project target if (target.IsBCLProject) { writer.WriteTarget ("clean{0}-bcl-sim{2}-{1}", "clean{0}-sim-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Clean succeeded"); // This is important, otherwise we'll end up executing the catch-all clean-% target writer.WriteLine (); } writer.WriteTarget ("clean{0}-sim{2}-{1}", string.Empty, make_escaped_suffix, make_escaped_name, target.ProjectPath.Replace (" ", "\\ "), target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q_XBUILD) $(SYSTEM_XBUILD) \"/property:Configuration=$(CONFIG)\" \"/property:Platform=iPhoneSimulator\" /t:Clean $(XBUILD_VERBOSITY) \"{0}\"", target.ProjectPath); writer.WriteLine (); // run sim project target if (target.IsMultiArchitecture) { writer.WriteTarget ("run{0}-sim{2}-{1}", string.Empty, make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) rm -f \".$@-failure.stamp\""); writer.WriteLine ("\t$(Q) $(MAKE) build{0}-sim{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-sim32-{1} || echo \"exec{0}-sim32-{1} failed\" >> \".$@-failure.stamp\"", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-sim64-{1} || echo \"exec{0}-sim64-{1} failed\" >> \".$@-failure.stamp\"", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); writer.WriteTarget ("run{0}-sim32-{1}", string.Empty, make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) build{0}-sim{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-sim32-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine (); writer.WriteTarget ("run{0}-sim64-{1}", string.Empty, make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) build{0}-sim{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-sim64-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine (); } else { writer.WriteTarget ("run{0}-sim{2}-{1}", string.Empty, make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) build{0}-sim{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-sim{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine (); } if (target.IsBCLProject && target.IsExe) { writer.WriteTarget ("run{0}-bcl-sim{2}-{1}", "run{0}-sim{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); if (target.IsMultiArchitecture) { writer.WriteTarget ("run{0}-bcl-sim32-{1}", "run{0}-sim32-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); writer.WriteTarget ("run{0}-bcl-sim64-{1}", "run{0}-sim64-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); } } if (target is ClassicTarget) { // target that runs both Classic+Unified writer.WriteTarget ("run{0}-sim-{1}", string.Empty, make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) rm -f \".$@-failure.stamp\""); writer.WriteLine ("\t$(Q) $(MAKE) build{0}-simclassic-{1} build{0}-simunified-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-simclassic-{1} || echo \"exec{0}-simclassic-{1} failed\" >> \".$@-failure.stamp\"", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-sim32-{1} || echo \"exec{0}-sim32-{1} failed\" >> \".$@-failure.stamp\"", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-sim64-{1} || echo \"exec{0}-sim64-{1} failed\" >> \".$@-failure.stamp\"", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); // compat targets for finger memory writer.WriteTarget ("run-simcompat-{1}", "run-ios-simclassic-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); writer.WriteTarget ("run-simdual-{1}", "run-ios-simunified-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); } // exec sim project target if (target.IsMultiArchitecture) { writer.WriteTarget ("exec{0}-sim64-{1}", "$(UNIT_SERVER)", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug xharness/xharness.exe $(XHARNESS_VERBOSITY) --run \"{0}\" --target {1}-simulator-64 --sdkroot $(XCODE_DEVELOPER_ROOT) --logdirectory \"$(abspath $(CURDIR))/logs/$@\" --configuration $(CONFIG)", target.ProjectPath, target.Platform); writer.WriteLine (); writer.WriteTarget ("exec{0}-sim32-{1}", "$(UNIT_SERVER)", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug xharness/xharness.exe $(XHARNESS_VERBOSITY) --run \"{0}\" --target {1}-simulator-32 --sdkroot $(XCODE_DEVELOPER_ROOT) --logdirectory \"$(abspath $(CURDIR))/logs/$@\" --configuration $(CONFIG)", target.ProjectPath, target.Platform); writer.WriteLine (); } else { writer.WriteTarget ("exec{0}-sim{2}-{1}", "$(UNIT_SERVER)", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug xharness/xharness.exe $(XHARNESS_VERBOSITY) --run \"{0}\" --target {1}-simulator --sdkroot $(XCODE_DEVELOPER_ROOT) --logdirectory \"$(abspath $(CURDIR))/logs/$@\" --configuration $(CONFIG)", target.ProjectPath, target.Platform); writer.WriteLine (); } if (target.IsBCLProject && target.IsExe) { writer.WriteTarget ("exec{0}-bcl-sim{2}-{1}", "exec{0}-sim-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Exec succeeded"); // This is important, otherwise we'll end up executing the catch-all exec-% target writer.WriteLine (); if (target.IsMultiArchitecture) { writer.WriteTarget ("exec{0}-bcl-sim32-{1}", "exec{0}-sim32-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Exec succeeded"); // This is important, otherwise we'll end up executing the catch-all exec-% target writer.WriteLine (); writer.WriteTarget ("exec{0}-bcl-sim64-{1}", "exec{0}-sim64-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Exec succeeded"); // This is important, otherwise we'll end up executing the catch-all exec-% target writer.WriteLine (); } } // build dev project target if (target.IsBCLProject) { writer.WriteTarget ("build{0}-bcl-dev{2}-{1}", "build{0}-dev-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Build succeeded"); // This is important, otherwise we'll end up executing the catch-all clean-% target writer.WriteLine (); } writer.WriteTarget ("build{0}-dev{3}-{1}", "{2} xharness/xharness.exe", make_escaped_suffix, make_escaped_name, target.ProjectPath.Replace (" ", "\\ "), target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q_XBUILD) $(SYSTEM_XBUILD) \"/property:Configuration=$(CONFIG)\" \"/property:Platform=iPhone\" /t:Build $(XBUILD_VERBOSITY) \"{0}\"", target.ProjectPath); writer.WriteLine (); if (target is ClassicTarget) { // target that builds both Classic+Unified writer.WriteTarget ("build{0}-dev-{1}", "build{0}-devclassic-{1} build{0}-devunified-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Build succeeded"); // This is important, otherwise we'll end up executing the catch-all build-% target writer.WriteLine (); } // clean dev project target if (target.IsBCLProject) { writer.WriteTarget ("clean{0}-bcl-dev{2}-{1}", "clean{0}-dev-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Clean succeeded"); // This is important, otherwise we'll end up executing the catch-all clean-% target writer.WriteLine (); } writer.WriteTarget ("clean{0}-dev{2}-{1}", string.Empty, make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q_XBUILD) $(SYSTEM_XBUILD) \"/property:Configuration=$(CONFIG)\" \"/property:Platform=iPhone\" /t:Clean $(XBUILD_VERBOSITY) \"{0}\"", target.ProjectPath); writer.WriteLine (); // install dev project target if (target.IsBCLProject) { writer.WriteTarget ("install{0}-bcl-dev{2}-{1}", "install{0}-dev-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Install succeeded"); // This is important, otherwise we'll end up executing the catch-all install-% target writer.WriteLine (); } writer.WriteTarget ("install{0}-dev{2}-{1}", "xharness/xharness.exe", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug xharness/xharness.exe $(XHARNESS_VERBOSITY) --install \"{0}\" --target {1}-device --sdkroot $(XCODE_DEVELOPER_ROOT) --configuration $(CONFIG)", target.ProjectPath, target.Platform); writer.WriteLine (); // run dev project target if (target.IsBCLProject) { writer.WriteTarget ("run{0}-bcl-dev{2}-{1}", "run{0}-dev-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); } writer.WriteTarget ("run{0}-dev{2}-{1}", "xharness/xharness.exe", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) build{0}-dev{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) install{0}-dev{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-dev{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine (); // exec dev project target if (target.IsBCLProject) { writer.WriteTarget ("exec{0}-bcl-dev{2}-{1}", "exec{0}-dev{2}-{1}", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) echo Exec succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); } writer.WriteTarget ("exec{0}-dev{2}-{1}", "xharness/xharness.exe", make_escaped_suffix, make_escaped_name, target.MakefileWhereSuffix); writer.WriteLine ("\t$(Q) rm -f \"$@.log\""); writer.WriteLine ("\t$(Q) $(SYSTEM_MONO) --debug xharness/xharness.exe $(XHARNESS_VERBOSITY) --run \"{0}\" --target {1}-device --sdkroot $(XCODE_DEVELOPER_ROOT) --configuration $(CONFIG)", target.ProjectPath, target.Platform); writer.WriteLine (); if (target is ClassicTarget) { // target that runs both Classic+Unified writer.WriteTarget ("run{0}-dev-{1}", string.Empty, make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) rm -f \".$@-failure.stamp\""); writer.WriteLine ("\t$(Q) $(MAKE) build{0}-devclassic-{1} build{0}-devunified-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) install{0}-devclassic-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-devclassic-{1} || echo \"exec{0}-devclassic-{1} failed\" >> \".$@-failure.stamp\"", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) install{0}-devunified-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) exec{0}-devunified-{1} || echo \"exec{0}-devunified-{1} failed\" >> \".$@-failure.stamp\"", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); // compat targets for finger memory writer.WriteTarget ("run-devcompat-{1}", "run-ios-devclassic-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); writer.WriteTarget ("run-devdual-{1}", "run-ios-devunified-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); } // targets that does both sim and device if (!(target is UnifiedTarget) /* exclude Unified so that we don't end up duplicating these targets */) { // build target writer.WriteTarget ("build{0}-{1}", "build{0}-dev-{1} build{0}-sim-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Build succeeded"); // This is important, otherwise we'll end up executing the catch-all build-% target writer.WriteLine (); // run target writer.WriteTarget ("run{0}-{1}", "run{0}-dev-{1} run{0}-sim-{1}", make_escaped_suffix, make_escaped_name); writer.WriteLine ("\t$(Q) echo Run succeeded"); // This is important, otherwise we'll end up executing the catch-all run-% target writer.WriteLine (); } } writer.WriteLine ("# Container targets that run multiple test projects"); writer.WriteLine (); writer.WriteLine ("run-local:"); // run every single test we have everywhere writer.WriteLine ("\t$(Q) rm -rf \".$@-failure.stamp\""); foreach (var target in allTargets) { if (!target.IsExe) continue; if (target is ClassicTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-simclassic-{1}\" || echo \"run{0}-simclassic-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-devclassic-{1}\" || echo \"run{0}-devclassic-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); } else if (target is UnifiedTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-simunified-{1}\" || echo \"run{0}-simunified-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-devunified-{1}\" || echo \"run{0}-devunified-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); } else { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-sim-{1}\" || echo \"run{0}-sim-{1} failed\" >> \".$@-failure.stamp\"", target.Suffix, target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-dev-{1}\" || echo \"run{0}-dev-{1} failed\" >> \".$@-failure.stamp\"", target.Suffix, target.Name); } } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); writer.WriteLine ("run-sim run-all-sim:"); // run every single test we have in the simulator writer.WriteLine ("\t$(Q) rm -rf \".$@-failure.stamp\""); foreach (var target in allTargets) { if (!target.IsExe) continue; if (target is ClassicTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-simcompat-{1}\" || echo \"run{0}-simcompat-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); } else if (target is UnifiedTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-simunified-{1}\" || echo \"run{0}-simunified-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); } else { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-sim-{1}\" || echo \"run{0}-sim-{1} failed\" >> \".$@-failure.stamp\"", target.Suffix, target.Name); } } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); writer.WriteLine ("run-dev run-all-dev:"); // run every single test we have on device writer.WriteLine ("\t$(Q) rm -rf \".$@-failure.stamp\""); foreach (var target in allTargets) { if (!target.IsExe) continue; if (target is ClassicTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-devcompat-{1}\" || echo \"run{0}-devcompat-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); } else if (target is UnifiedTarget) { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-devunified-{1}\" || echo \"run{0}-devunified-{1} failed\" >> \".$@-failure.stamp\"", "-ios", target.Name); } else { writer.WriteLine ("\t$(Q) $(MAKE) \"run{0}-dev-{1}\" || echo \"run{0}-dev-{1} failed\" >> \".$@-failure.stamp\"", target.Suffix, target.Name); } } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); foreach (var mode in new string [] { "sim", "dev" }) { WriteCollectionTarget (writer, "run-ios-" + mode, allTargets.Where ((v) => v.IsExe && (v is ClassicTarget || v is UnifiedTarget)), mode); WriteCollectionTarget (writer, "run-tvos-" + mode, tvos_targets.Where ((v) => v.IsExe), mode); WriteCollectionTarget (writer, "run-watchos-" + mode, watchos_targets.Where ((v) => v.IsExe), mode); } writer.WriteLine (); writer.WriteLine ("build build-all:"); // build everything writer.WriteLine ("\t$(Q) rm -rf \".$@-failure.stamp\""); foreach (var target in classic_targets) { if (!target.IsExe) continue; writer.WriteLine ("\t$(Q) $(MAKE) \"build-sim-{0}\" \"build-dev-{0}\" || echo \"build-{0} failed\" >> \".$@-failure.stamp\"", target.Name); } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); // targets that run all platforms writer.WriteLine (); foreach (var target in classic_targets) { if (!target.IsExe) continue; var make_escaped_name = target.Name.Replace (" ", "\\ "); writer.WriteTarget ("build-sim-{0}", "build-ios-simclassic-{0} build-ios-simunified-{0} build-tvos-sim-{0} build-watchos-sim-{0}", make_escaped_name); writer.WriteLine ("\t$(Q) echo Simulator builds succeeded"); // This is important, otherwise we'll end up executing the catch-all build-% target writer.WriteLine (); writer.WriteTarget ("build-dev-{0}", "build-ios-devclassic-{0} build-ios-devunified-{0} build-tvos-dev-{0} build-watchos-dev-{0}", make_escaped_name); writer.WriteLine ("\t$(Q) echo Device builds succeeded"); // This is important, otherwise we'll end up executing the catch-all build-% target writer.WriteLine (); writer.WriteTarget ("build-{0}", "build-sim-{0} build-dev-{0}", make_escaped_name); writer.WriteLine ("\t$(Q) echo Build succeeded"); // This is important, otherwise we'll end up executing the catch-all build-% target writer.WriteLine (); writer.WriteTarget ("run-sim-{0}", "build-sim-{0}", make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-simclassic-{0}\" || echo \"exec-sim-iosclassic-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-sim32-{0}\" || echo \"exec-ios-sim32-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-sim64-{0}\" || echo \"exec-ios-sim64-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-tvos-sim-{0}\" || echo \"exec-tvos-sim-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-watchos-sim-{0}\" || echo \"exec-watchos-sim-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); writer.WriteTarget ("run-dev-{0}", "build-dev-{0}", make_escaped_name); writer.WriteLine ("\t$(Q) $(MAKE) \"install-ios-devclassic-{0}\" || echo \"install-ios-devclassic-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-devclassic-{0}\" || echo \"exec-ios-devclassic-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"install-ios-devunified-{0}\" || echo \"install-ios-devunified-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-devunified-{0}\" || echo \"exec-ios-devunified-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"install-tvos-dev-{0}\" || echo \"install-tvos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-tvos-dev-{0}\" || echo \"exec-tvos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"install-watchos-dev-{0}\" || echo \"install-watchos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-watchos-dev-{0}\" || echo \"exec-watchos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); writer.WriteTarget ("run-{0}", "build-{0}", make_escaped_name); // sim writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-simclassic-{0}\" || echo \"exec-sim-iosclassic-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-sim32-{0}\" || echo \"exec-ios-sim32-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-sim64-{0}\" || echo \"exec-ios-sim64-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-tvos-sim-{0}\" || echo \"exec-tvos-sim-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-watchos-sim-{0}\" || echo \"exec-watchos-sim-{0} failed\" >> \".$@-failure.stamp\"", target.Name); // dev writer.WriteLine ("\t$(Q) $(MAKE) \"install-ios-devclassic-{0}\" || echo \"install-ios-devclassic-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-devclassic-{0}\" || echo \"exec-ios-devclassic-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"install-ios-devunified-{0}\" || echo \"install-ios-devunified-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-ios-devunified-{0}\" || echo \"exec-ios-devunified-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"install-tvos-dev-{0}\" || echo \"install-tvos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-tvos-dev-{0}\" || echo \"exec-tvos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"install-watchos-dev-{0}\" || echo \"install-watchos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"exec-watchos-dev-{0}\" || echo \"exec-watchos-dev-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); // Wrench needs a slightly different approach, because we want to run some tests, even if other tests failed to build // (the default is to build all, then run all if everything built). The problem is that there's no way (that I've found) // to make the build parallelizable and support the wrench mode at the same time. writer.WriteLine ("wrenchhelper-{0}:", make_escaped_name); writer.WriteLine ("\t$(Q) rm -f \".$@-failure.stamp\" \".$@-ios-simunified-build-failure.stamp\" \".$@-tvos-sim-build-failure.stamp\" \".$@-watchos-sim-build-failure.stamp\""); writer.WriteLine ("\t$(Q) echo \"@MonkeyWrench: SetSummary:\""); // first build (serialized) writer.WriteLine ("\t$(Q) $(MAKE) \"build-ios-simunified-{0}\" || echo \"@MonkeyWrench: AddSummary: unified failed to build
\" >> \".$@-ios-simunified-build-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) $(MAKE) \"build-tvos-sim-{0}\" || echo \"@MonkeyWrench: AddSummary: tvos failed to build
\" >> \".$@-tvos-sim-build-failure.stamp\"", target.Name); if (harness.INCLUDE_WATCH) writer.WriteLine ("\t$(Q) $(MAKE) \"build-watchos-sim-{0}\" || echo \"@MonkeyWrench: AddSummary: watchos failed to build
\" >> \".$@-watchos-sim-build-failure.stamp\"", target.Name); // then run writer.WriteLine ("\t$(Q) (test -e \".$@-ios-simunified-build-failure.stamp\" && cat \".$@-ios-simunified-build-failure.stamp\" >> \".$@-failure.stamp\") || $(MAKE) \"exec-ios-sim32-{0}\" || echo \"exec-ios-sim32-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) test -e \".$@-ios-simunified-build-failure.stamp\" || $(MAKE) \"exec-ios-sim64-{0}\" || echo \"exec-ios-sim64-{0} failed\" >> \".$@-failure.stamp\"", target.Name); writer.WriteLine ("\t$(Q) (test -e \".$@-tvos-sim-build-failure.stamp\" && cat \".$@-tvos-sim-build-failure.stamp\" >> \".$@-failure.stamp\") || $(MAKE) \"exec-tvos-sim-{0}\" || echo \"exec-tvos-sim-{0} failed\" >> \".$@-failure.stamp\"", target.Name); if (harness.INCLUDE_WATCH) { if (harness.DisableWatchOSOnWrench) { writer.WriteLine ("\t$(Q) (test -e \".$@-watchos-sim-build-failure.stamp\" && cat \".$@-watchos-sim-build-failure.stamp\" ) || $(MAKE) \"exec-watchos-sim-{0}\" || echo \"exec-watchos-sim-{0} failed\" ", target.Name); } else { writer.WriteLine ("\t$(Q) (test -e \".$@-watchos-sim-build-failure.stamp\" && cat \".$@-watchos-sim-build-failure.stamp\" >> \".$@-failure.stamp\") || $(MAKE) \"exec-watchos-sim-{0}\" || echo \"exec-watchos-sim-{0} failed\" >> \".$@-failure.stamp\"", target.Name); } } writer.WriteLine ("\t$(Q) if test -e \".$@-failure.stamp\"; then cat \".$@-failure.stamp\"; rm \".$@-failure.stamp\"; exit 1; fi"); writer.WriteLine (); } writer.WriteLine (); } } } }