diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileNativeCode.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileNativeCode.cs index cc3332f6b61d..4eb61aaf4d41 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileNativeCode.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileNativeCode.cs @@ -37,6 +37,11 @@ public class CompileNativeCode : XamarinTask, ICancelableTask, ITaskCallback { public string DotNetRoot { get; set; } = ""; #endregion + #region Outputs + [Output] + public ITaskItem [] CompiledOutputFiles { get; set; } = Array.Empty (); + #endregion + public override bool Execute () { if (ShouldExecuteRemotely ()) { @@ -70,10 +75,10 @@ public override bool Execute () var compileInfo = sortedCompileInfo.Select (v => v.Item).ToArray (); var processes = new Task [compileInfo.Length]; + var outputFiles = new string [compileInfo.Length]; for (var i = 0; i < compileInfo.Length; i++) { var info = compileInfo [i]; - var src = Path.GetFullPath (info.ItemSpec); var arguments = new List (); arguments.Add ("clang"); @@ -124,9 +129,12 @@ public override bool Execute () arguments.AddRange (parsed_args); + var src = info.ItemSpec; var outputFile = info.GetMetadata ("OutputFile"); if (string.IsNullOrEmpty (outputFile)) outputFile = Path.ChangeExtension (src, ".o"); + outputFiles [i] = outputFile; // We keep the relative path for remote builds + src = Path.GetFullPath (src); outputFile = Path.GetFullPath (outputFile); arguments.Add ("-o"); arguments.Add (outputFile); @@ -139,6 +147,11 @@ public override bool Execute () System.Threading.Tasks.Task.WaitAll (processes); + // Collect all output files (regardless of compilation success) + CompiledOutputFiles = outputFiles + .Select (file => new TaskItem (file)) + .ToArray (); + return !Log.HasLoggedErrors; } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/ILLink.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/ILLink.cs index 1973eb57cc52..a8fd5b7828c5 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/ILLink.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/ILLink.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Tasks; using Microsoft.Build.Utilities; @@ -10,7 +11,7 @@ #nullable enable namespace Xamarin.MacDev.Tasks { - public class ILLink : global::ILLink.Tasks.ILLink { + public class ILLink : global::ILLink.Tasks.ILLink, ITaskCallback { public string SessionId { get; set; } = string.Empty; public ITaskItem [] DebugSymbols { get; set; } = Array.Empty (); @@ -18,9 +19,15 @@ public class ILLink : global::ILLink.Tasks.ILLink { [Required] public string LinkerItemsDirectory { get; set; } = string.Empty; + [Required] + public string LinkerCacheDirectory { get; set; } = string.Empty; + [Output] public ITaskItem [] LinkerOutputItems { get; set; } = Array.Empty (); + [Output] + public ITaskItem [] LinkerCacheItems { get; set; } = Array.Empty (); + [Output] public ITaskItem [] LinkedItems { get; set; } = Array.Empty (); @@ -29,26 +36,17 @@ public override bool Execute () if (this.ShouldExecuteRemotely (SessionId)) return new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result; + // Capture execution start time for Mac-side detection + var executionStartTime = DateTime.UtcNow; var result = base.Execute (); - var linkerItems = new List (); - var linkedItems = new List (); - if (result) { - // Adds all the files in the linker-items dir - foreach (var item in Directory.EnumerateFiles (LinkerItemsDirectory)) { - linkerItems.Add (new TaskItem (item)); - } - - // Adds all the files in the linked output dir - foreach (var item in Directory.EnumerateFiles (OutputDirectory.ItemSpec)) { - linkedItems.Add (new TaskItem (item)); - } + // Collect all files and tag those modified during this execution + LinkerOutputItems = GetAllFilesWithMetadata (LinkerItemsDirectory, executionStartTime); + LinkedItems = GetAllFilesWithMetadata (OutputDirectory.ItemSpec, executionStartTime); + LinkerCacheItems = GetAllFilesWithMetadata (LinkerCacheDirectory, executionStartTime); } - LinkerOutputItems = linkerItems.ToArray (); - LinkedItems = linkedItems.ToArray (); - return result; } @@ -59,5 +57,53 @@ public override void Cancel () else base.Cancel (); } + + ITaskItem [] GetAllFilesWithMetadata (string directory, DateTime executionStartTime) + { + if (string.IsNullOrEmpty (directory) || !Directory.Exists (directory)) + return Array.Empty (); + + return Directory.EnumerateFiles (directory, "*", SearchOption.AllDirectories) + .Select (file => { + var fileInfo = new FileInfo (file); + var item = new TaskItem (file); + + // Check if file was created or modified during this execution + var wasModified = fileInfo.CreationTimeUtc >= executionStartTime || + fileInfo.LastWriteTimeUtc >= executionStartTime; + + // Tag files that were modified during this execution + item.SetMetadata ("Modified", wasModified.ToString ()); + + return item; + }) + .ToArray (); + } + + // ITaskCallback implementation + public bool ShouldCopyToBuildServer (ITaskItem item) => true; + + public bool ShouldCreateOutputFile (ITaskItem item) + { + var modifiedMetadata = item.GetMetadata ("Modified"); + var wasModified = bool.TryParse (modifiedMetadata, out var modified) && modified; + + // Create output file if it was modified during this execution + if (wasModified) { + Log.LogMessage (MessageImportance.Low, "Output file '{0}' was modified during execution", item.ItemSpec); + return true; + } + + // Create output file if it doesn't exist on Windows. We assume if it exists on the Mac we also need it on Windows. + if (!File.Exists (item.ItemSpec)) { + Log.LogMessage (MessageImportance.Low, "Output file '{0}' does not exist", item.ItemSpec); + return true; + } + + Log.LogMessage (MessageImportance.Low, "Output file '{0}' exists and was not modified", item.ItemSpec); + return false; + } + + public IEnumerable GetAdditionalItemsToBeCopied () => Array.Empty (); } } diff --git a/msbuild/Xamarin.iOS.Tasks.Windows/Xamarin.iOS.Common.After.targets b/msbuild/Xamarin.iOS.Tasks.Windows/Xamarin.iOS.Common.After.targets index 781953fb30e3..18f47cefeb98 100644 --- a/msbuild/Xamarin.iOS.Tasks.Windows/Xamarin.iOS.Common.After.targets +++ b/msbuild/Xamarin.iOS.Tasks.Windows/Xamarin.iOS.Common.After.targets @@ -419,11 +419,10 @@ Copyright (C) 2011-2013 Xamarin. All rights reserved. ToolPath="$(_DotNetHostDirectory)" ILLinkPath="$(_RemoteILLinkPath)" LinkerItemsDirectory="$(_LinkerItemsDirectory)" + LinkerCacheDirectory="$(_LinkerCacheDirectory)" DebugSymbols="@(_ILLinkDebugSymbols)" ContinueOnError="ErrorAndContinue"> - -