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:
Родитель
282d107a02
Коммит
d89b6390f1
|
@ -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.");
|
||||
|
|
Загрузка…
Ссылка в новой задаче