Update AOTCompile task to handle cycles in up-to-date check (#20103)

#### Background

While cyclic assembly references are unusual they are supported by the runtime and encountered in practice. In our project we use a version of Xamarin.Forms retargeted for a modern .NET (as a stopgap solution before an update to full MAUI stack). Xamarin.Forms historically come with such an assembly cycle: `Xamarin.Forms.Core.dll` -> `Xamarin.Forms.Platform.dll` -> `Xamarin.Forms.Platform.iOS.dll` -> `Xamarin.Forms.Core.dll`. This is produced by first compiling `Xamarin.Forms.Core.dll` against a dummy `Xamarin.Forms.Platform.dll` (`netstandard2.0` assembly). Then the Platform assemblies are built, and finally forwarder versions of `Xamarin.Forms.Platform.dll` are created for each platform. This is all packaged into NuGets in such a way that each TFM gets the same `Xamarin.Forms.Core.dll` but a different set of `Xamarin.Forms.Platform.dll` and `Xamarin.Forms.Platform.<platform>.dll` assemblies.

#### Problem

With current workloads each incremental rebuild fails with:

```
/usr/local/share/dotnet/packs/Microsoft.iOS.Sdk/16.4.7125/targets/Xamarin.Shared.Sdk.targets(1047,3): error : Encountered an assembly reference cycle related to the assembly obj/Debug/net7.0-ios/iossimulator-arm64/linked/Xamarin.Forms.Core.dll
```

#### Solution

The PR updates the algorithm in `AOTCompile` to detect cycles using [Tarjan's algorithm](https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm) for finding [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component) in a graph. When a cycle is detect any assembly in the cycle is considered up-to-date only if all the assemblies in the cycle are up-to-date.

With this change the project does incremental rebuilds correctly. I verified in the build output that the assembly cycle is considered up-to-date, and that any changes to the application assemblies still return `false` from the up-to-date check and get rebuilt.

---------

Co-authored-by: Filip Navara <filip.navara@gmail.com>
This commit is contained in:
Filip Navara 2024-02-15 17:29:18 +01:00 коммит произвёл GitHub
Родитель 282d107a02
Коммит d89b6390f1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
28 изменённых файлов: 120 добавлений и 241 удалений

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Byl zjištěn cyklus odkazu na sestavení související se sestavením {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Es wurde ein Assemblyverweiszyklus gefunden, der mit der Assembly {0} verknüpft ist.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Se encontró un ciclo de referencia de ensamblado relacionado con el ensamblado {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[A rencontré un cycle de référence d'assemblage lié à l'assemblage {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[È stato rilevato un ciclo di riferimento dell'assembly correlato all'assembly {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[アセンブリ {0} に関連するアセンブリ参照サイクルが発生しました。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[{0} 어셈블리와 관련된 어셈블리 참조 주기를 발견했습니다.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Napotkano cykl odwołania do zestawu powiązany z zestawem {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Foi encontrado um ciclo de referência de assembly relacionado ao assembly {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Обнаружен цикл ссылки на сборку, связанный со сборкой {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[{0} bütünleştirilmiş koduyla ilgili bir bütünleştirilmiş kod başvuru döngüsüyle karşılaşıldı.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[遇到与程序集 {0} 相关的程序集引用周期。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1939,15 +1939,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";E7119" ItemType="0;.resx" PsrId="211" InstFlg="true" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Encountered an assembly reference cycle related to the assembly {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[遇到與組件 {0} 相關的組件參考循環。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";InvalidFramework" ItemType="0;.resx" PsrId="211" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Invalid framework: {0}]]></Val>

Просмотреть файл

@ -1533,11 +1533,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>Encountered an assembly reference cycle related to the assembly {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>Byl zjištěn cyklus odkazu na sestavení související se sestavením {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>Es wurde ein Assemblyverweiszyklus gefunden, der mit der Assembly {0} verknüpft ist.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>Se encontró un ciclo de referencia de ensamblado relacionado con el ensamblado {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>A rencontré un cycle de référence d'assemblage lié à l'assemblage {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>È stato rilevato un ciclo di riferimento dell'assembly correlato all'assembly {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>アセンブリ {0} に関連するアセンブリ参照サイクルが発生しました。</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>{0} 어셈블리와 관련된 어셈블리 참조 주기를 발견했습니다.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>Napotkano cykl odwołania do zestawu powiązany z zestawem {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>Foi encontrado um ciclo de referência de assembly relacionado ao assembly {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>Обнаружен цикл ссылки на сборку, связанный со сборкой {0}.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>{0} bütünleştirilmiş koduyla ilgili bir bütünleştirilmiş kod başvuru döngüsüyle karşılaşıldı.</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>遇到与程序集 {0} 相关的程序集引用周期。</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -1237,10 +1237,4 @@
{1}: the exit code of a process
</comment>
</data>
<data name="E7119" xml:space="preserve">
<value>遇到與組件 {0} 相關的組件參考循環。</value>
<comment>
{0}: the path to an assembly
</comment>
</data>
</root>

Просмотреть файл

@ -47,7 +47,12 @@ namespace Xamarin.MacDev.Tasks {
class AssemblyInfo {
public ITaskItem TaskItem;
public bool? IsUpToDate;
public bool IsUpToDate;
// Tarjan's SCC algoritm
public bool OnStack;
public int Index;
public int LowLink;
public AssemblyInfo (ITaskItem item)
{
@ -62,26 +67,114 @@ namespace Xamarin.MacDev.Tasks {
return Path.GetFileNameWithoutExtension (item.ItemSpec);
}
bool IsUpToDate (ITaskItem assembly)
bool ComputeUpToDate (IEnumerable<ITaskItem> items)
{
var assemblyPath = assembly.ItemSpec;
var key = GetAssemblyName (assembly);
if (assemblyInfos.TryGetValue (key, out var info)) {
if (!info.IsUpToDate.HasValue) {
Log.LogError (MSBStrings.E7119 /* Encountered an assembly reference cycle related to the assembly {0}. */, assemblyPath);
info.IsUpToDate = false;
return false;
// Implements Tarjan's algorithm for finding strongly connected components.
// https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
//
// We recursively compute up-to-date state for each assembly and its references.
// When we encounter a strongly connected component (cycle) we ensure that either
// all the files in the SCC are marked as up-to-date or none.
int index = 0;
var stack = new Stack<AssemblyInfo> ();
bool success = true;
foreach (ITaskItem assembly in items) {
var key = GetAssemblyName (assembly);
if (!assemblyInfos.ContainsKey (key)) {
var info = new AssemblyInfo (assembly);
assemblyInfos [key] = info;
success &= ComputeUpToDate (info, stack, ref index);
}
return info.IsUpToDate.Value;
}
info = new AssemblyInfo (assembly);
assemblyInfos [key] = info;
return success;
}
bool ComputeUpToDate (AssemblyInfo info, Stack<AssemblyInfo> stack, ref int index)
{
bool success = true;
info.Index = index;
info.LowLink = index;
index++;
stack.Push (info);
info.OnStack = true;
info.IsUpToDate = ComputeUpToDate (info.TaskItem);
// Walk all referenced assemblies
var assemblyPath = info.TaskItem.ItemSpec;
using var ad = AssemblyDefinition.ReadAssembly (assemblyPath, new ReaderParameters { ReadingMode = ReadingMode.Deferred });
foreach (var ar in ad.MainModule.AssemblyReferences) {
var referencedItems = Assemblies.Where (v => string.Equals (GetAssemblyName (v), ar.Name, StringComparison.OrdinalIgnoreCase)).ToArray ();
if (referencedItems.Length == 0) {
Log.LogMessage (MessageImportance.Low, $"Ignoring unresolved assembly {ar.Name} (referenced from {assemblyPath}).");
continue;
} else if (referencedItems.Length > 1) {
Log.LogError (MSBStrings.E7117 /* The assembly {0} was passed multiple times as an input assembly (referenced from {1}). */, ar.Name, assemblyPath);
success = false;
continue;
}
var referencedItem = referencedItems [0];
var key = GetAssemblyName (referencedItem);
if (!assemblyInfos.TryGetValue (key, out var referenceInfo)) {
// Referenced assembly has not yet been visited; recurse on it
referenceInfo = new AssemblyInfo (referencedItem);
assemblyInfos [key] = referenceInfo;
success &= ComputeUpToDate (referenceInfo, stack, ref index);
if (info.IsUpToDate && !referenceInfo.IsUpToDate) {
Log.LogMessage (MessageImportance.Low, $"The assembly {assemblyPath} is not up-to-date with regards to the reference {referenceInfo.TaskItem.ItemSpec}.");
info.IsUpToDate = false;
}
info.LowLink = Math.Min (info.LowLink, referenceInfo.LowLink);
} else if (referenceInfo.OnStack) {
// Referenced assembly is in stack and hence in the current SCC
info.LowLink = Math.Min (info.LowLink, referenceInfo.Index);
}
}
// If this is a root node of SCC, pop the stack
if (info.Index == info.LowLink) {
bool sccIsUpToDate = true;
// Walk the SCC on the stack and determine whether the whole
// component is up-to-date or not.
foreach (var itemOnStack in stack) {
if (itemOnStack == info) {
break;
}
sccIsUpToDate &= itemOnStack.IsUpToDate;
}
// Remove the SCC from the stack and update IsUpToDate for each item.
AssemblyInfo popped;
do {
popped = stack.Pop ();
popped.OnStack = false;
if (!sccIsUpToDate) {
// If any assembly in the SCC is not up-to-date then the whole SCC is not
// up to date.
popped.IsUpToDate = false;
Log.LogMessage (MessageImportance.Low, $"The assembly {popped.TaskItem.ItemSpec} in a cycle is not up-to-date.");
} else {
Log.LogMessage (MessageImportance.Low, $"The AOT-compiled code for {popped.TaskItem.ItemSpec} is up-to-date.");
}
} while (popped != info);
}
return success;
}
bool ComputeUpToDate (ITaskItem assembly)
{
var assemblyPath = assembly.ItemSpec;
var finfo = new FileInfo (assemblyPath);
if (!finfo.Exists) {
Log.LogError (MSBStrings.E0158 /* The file {0} does not exist. */, assemblyPath);
info.IsUpToDate = false;
return false;
}
@ -89,13 +182,11 @@ namespace Xamarin.MacDev.Tasks {
var objectFile = assembly.GetMetadata ("ObjectFile");
if (string.IsNullOrEmpty (objectFile)) {
Log.LogError (MSBStrings.E7116 /* The assembly {0} does not provide an 'ObjectFile' metadata. */, assembly.ItemSpec);
info.IsUpToDate = false;
return false;
}
var objectFileInfo = new FileInfo (objectFile);
if (!IsUpToDate (finfo, objectFileInfo)) {
Log.LogMessage (MessageImportance.Low, "The assembly {0} is not up-to-date with regards to the object file {1}", assemblyPath, objectFile);
info.IsUpToDate = false;
return false;
}
@ -105,37 +196,24 @@ namespace Xamarin.MacDev.Tasks {
var llvmFileInfo = new FileInfo (llvmFile);
if (!IsUpToDate (finfo, llvmFileInfo)) {
Log.LogMessage (MessageImportance.Low, "The assembly {0} is not up-to-date with regards to the llvm file {1}", assemblyPath, llvmFile);
info.IsUpToDate = false;
return false;
}
}
// We know now the assembly itself is up-to-date, but what about every referenced assembly?
// This assembly must be AOT-compiled again if any referenced assembly has changed as well.
using var ad = AssemblyDefinition.ReadAssembly (assembly.ItemSpec, new ReaderParameters { ReadingMode = ReadingMode.Deferred });
foreach (var ar in ad.MainModule.AssemblyReferences) {
var referencedItems = Assemblies.Where (v => string.Equals (GetAssemblyName (v), ar.Name, StringComparison.OrdinalIgnoreCase)).ToArray ();
if (referencedItems.Length == 0) {
Log.LogMessage (MessageImportance.Low, $"Ignoring unresolved assembly {ar.Name} (referenced from {assemblyPath}).");
continue;
} else if (referencedItems.Length > 1) {
Log.LogError (MSBStrings.E7117 /* The assembly {0} was passed multiple times as an input assembly (referenced from {1}). */, ar.Name, assemblyPath);
info.IsUpToDate = false;
return false;
}
var referencedItem = referencedItems [0];
if (!IsUpToDate (referencedItem)) {
info.IsUpToDate = false;
Log.LogMessage (MessageImportance.Low, "The assembly {0} is not up-to-date with regards to the reference {1}", assemblyPath, ar.Name);
return false;
}
}
Log.LogMessage (MessageImportance.Low, $"The AOT-compiled code for {assemblyPath} is up-to-date.");
info.IsUpToDate = true;
return true;
}
bool IsUpToDate (ITaskItem assembly)
{
var assemblyPath = assembly.ItemSpec;
var key = GetAssemblyName (assembly);
if (assemblyInfos.TryGetValue (key, out var info)) {
return info.IsUpToDate;
}
return false;
}
bool IsUpToDate (FileInfo input, FileInfo output)
{
if (!output.Exists)
@ -171,6 +249,9 @@ namespace Xamarin.MacDev.Tasks {
}
// Figure out which assemblies need to be aot'ed, and which are up-to-date.
if (!ComputeUpToDate (Assemblies)) {
return false;
}
var assembliesToAOT = Assemblies.Where (asm => !IsUpToDate (asm)).ToList ();
if (assembliesToAOT.Count == 0) {
Log.LogMessage (MessageImportance.Low, $"All the AOT-compiled code is up-to-date.");