/// <summary> /// Patches a set of actions for use with live coding. The new action list will output object files to a different location. /// </summary> /// <param name="Actions">Set of actions</param> /// <param name="OriginalFileToPatchedFile">Dictionary that receives a map of original object file to patched object file</param> public static void PatchActionGraphForLiveCoding(IEnumerable <Action> Actions, Dictionary <FileReference, FileReference> OriginalFileToPatchedFile) { foreach (Action Action in Actions) { if (Action.ActionType == ActionType.Compile) { if (!Action.CommandPath.GetFileName().Equals("cl-filter.exe", StringComparison.OrdinalIgnoreCase)) { throw new BuildException("Unable to patch action graph - unexpected executable in compile action ({0})", Action.CommandPath); } List <string> Arguments = Utils.ParseArgumentList(Action.CommandArguments); // Find the index of the cl-filter argument delimiter int DelimiterIdx = Arguments.IndexOf("--"); if (DelimiterIdx == -1) { throw new BuildException("Unable to patch action graph - missing '--' delimiter to cl-filter"); } // Fix the dependencies path const string DependenciesPrefix = "-dependencies="; int DependenciesIdx = 0; for (;; DependenciesIdx++) { if (DependenciesIdx == DelimiterIdx) { throw new BuildException("Unable to patch action graph - missing '{0}' argument to cl-filter", DependenciesPrefix); } else if (Arguments[DependenciesIdx].StartsWith(DependenciesPrefix, StringComparison.OrdinalIgnoreCase)) { break; } } FileReference OldDependenciesFile = new FileReference(Arguments[DependenciesIdx].Substring(DependenciesPrefix.Length)); FileItem OldDependenciesFileItem = Action.ProducedItems.First(x => x.Location == OldDependenciesFile); Action.ProducedItems.Remove(OldDependenciesFileItem); FileReference NewDependenciesFile = OldDependenciesFile.ChangeExtension(".lc.response"); FileItem NewDependenciesFileItem = FileItem.GetItemByFileReference(NewDependenciesFile); Action.ProducedItems.Add(NewDependenciesFileItem); Arguments[DependenciesIdx] = DependenciesPrefix + NewDependenciesFile.FullName; // Fix the response file int ResponseFileIdx = DelimiterIdx + 1; for (; ; ResponseFileIdx++) { if (ResponseFileIdx == Arguments.Count) { throw new BuildException("Unable to patch action graph - missing response file argument to cl-filter"); } else if (Arguments[ResponseFileIdx].StartsWith("@", StringComparison.Ordinal)) { break; } } FileReference OldResponseFile = new FileReference(Arguments[ResponseFileIdx].Substring(1)); FileReference NewResponseFile = new FileReference(OldResponseFile.FullName + ".lc"); const string OutputFilePrefix = "/Fo"; string[] ResponseLines = FileReference.ReadAllLines(OldResponseFile); for (int Idx = 0; Idx < ResponseLines.Length; Idx++) { string ResponseLine = ResponseLines[Idx]; if (ResponseLine.StartsWith(OutputFilePrefix, StringComparison.Ordinal)) { FileReference OldOutputFile = new FileReference(ResponseLine.Substring(3).Trim('\"')); FileItem OldOutputFileItem = Action.ProducedItems.First(x => x.Location == OldOutputFile); Action.ProducedItems.Remove(OldOutputFileItem); FileReference NewOutputFile = OldOutputFile.ChangeExtension(".lc.obj"); FileItem NewOutputFileItem = FileItem.GetItemByFileReference(NewOutputFile); Action.ProducedItems.Add(NewOutputFileItem); OriginalFileToPatchedFile[OldOutputFile] = NewOutputFile; ResponseLines[Idx] = OutputFilePrefix + "\"" + NewOutputFile.FullName + "\""; break; } } FileReference.WriteAllLines(NewResponseFile, ResponseLines); Arguments[ResponseFileIdx] = "@" + NewResponseFile.FullName; // Update the final arguments Action.CommandArguments = Utils.FormatCommandLine(Arguments); } } }