diff --git a/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets b/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets index 3fd4a7880e1f..ce76e7136831 100644 --- a/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets +++ b/corebuild/integration/ILLink.Tasks/ILLink.Tasks.targets @@ -222,7 +222,7 @@ the future we will want to generate these depending on the scenario in which the linker is invoked. --> - -t -l none -b true + -t -l none -b true --skip-unresolved true _assemblies; + HashSet _unresolvedAssemblies; + bool _ignoreUnresolved; + LinkContext _context; public IDictionary AssemblyCache { get { return _assemblies; } @@ -55,12 +58,32 @@ public AssemblyResolver (Dictionary assembly_cache) _assemblies = assembly_cache; } + public bool IgnoreUnresolved { + get { return _ignoreUnresolved; } + set { _ignoreUnresolved = value; } + } + + public LinkContext Context { + get { return _context; } + set { _context = value; } + } + public override AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters) { - AssemblyDefinition asm; - if (!_assemblies.TryGetValue (name.Name, out asm)) { - asm = base.Resolve (name, parameters); - _assemblies [asm.Name.Name] = asm; + AssemblyDefinition asm = null; + if (!_assemblies.TryGetValue (name.Name, out asm) && (_unresolvedAssemblies == null || !_unresolvedAssemblies.Contains (name.Name))) { + try { + asm = base.Resolve (name, parameters); + _assemblies [name.Name] = asm; + } catch (AssemblyResolutionException) { + if (!_ignoreUnresolved) + throw; + + _context.LogMessage ($"warning: unresolved assembly {name.Name}"); + if (_unresolvedAssemblies == null) + _unresolvedAssemblies = new HashSet (); + _unresolvedAssemblies.Add (name.Name); + } } return asm; @@ -80,6 +103,8 @@ protected override void Dispose (bool disposing) } _assemblies.Clear (); + if (_unresolvedAssemblies != null) + _unresolvedAssemblies.Clear (); } } } diff --git a/linker/Linker/Driver.cs b/linker/Linker/Driver.cs index 26ebe038e938..35f03edf63ba 100644 --- a/linker/Linker/Driver.cs +++ b/linker/Linker/Driver.cs @@ -106,7 +106,9 @@ public void Run (ILogger customLogger = null) Usage ("Option is too short"); if (token == "--skip-unresolved") { - context.IgnoreUnresolved = bool.Parse (GetParam ()); + bool ignoreUnresolved = bool.Parse (GetParam ()); + context.IgnoreUnresolved = ignoreUnresolved; + context.Resolver.IgnoreUnresolved = ignoreUnresolved; continue; } @@ -343,7 +345,7 @@ static void Usage (string msg) Console.WriteLine (" --about About the {0}", _linker); Console.WriteLine (" --version Print the version number of the {0}", _linker); - Console.WriteLine (" --skip-unresolved Ignore unresolved types and methods (true or false)"); + Console.WriteLine (" --skip-unresolved Ignore unresolved types, methods, and assemblies (true or false)"); Console.WriteLine (" --dependencies-file Specify the dependencies file path, if unset the default path is used: /linker-dependencies.xml.gz"); Console.WriteLine (" --dump-dependencies Dump dependencies for the linker analyzer tool"); Console.WriteLine (" --reduced-tracing Reduces dependency output related to assemblies that will not be modified"); diff --git a/linker/Linker/LinkContext.cs b/linker/Linker/LinkContext.cs index a87d7dbc3eae..9339df33e617 100644 --- a/linker/Linker/LinkContext.cs +++ b/linker/Linker/LinkContext.cs @@ -158,6 +158,7 @@ public LinkContext (Pipeline pipeline, AssemblyResolver resolver, ReaderParamete { _pipeline = pipeline; _resolver = resolver; + _resolver.Context = this; _actions = new Dictionary (); _parameters = new Dictionary (); _readerParameters = readerParameters; @@ -208,7 +209,7 @@ public AssemblyDefinition Resolve (IMetadataScope scope) try { AssemblyDefinition assembly = _resolver.Resolve (reference, _readerParameters); - if (SeenFirstTime (assembly)) { + if (assembly != null && SeenFirstTime (assembly)) { SafeReadSymbols (assembly); SetAction (assembly); } @@ -248,11 +249,9 @@ public virtual ICollection ResolveReferences (AssemblyDefini { List references = new List (); foreach (AssemblyNameReference reference in assembly.MainModule.AssemblyReferences) { - try { - references.Add (Resolve (reference)); - } - catch (AssemblyResolutionException) { - } + AssemblyDefinition definition = Resolve (reference); + if (definition != null) + references.Add (definition); } return references; } diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/SkipUnresolvedAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/SkipUnresolvedAttribute.cs new file mode 100644 index 000000000000..bee9a7f4fc86 --- /dev/null +++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/SkipUnresolvedAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Mono.Linker.Tests.Cases.Expectations.Metadata { + public sealed class SkipUnresolvedAttribute : BaseMetadataAttribute { + public readonly bool Value; + + public SkipUnresolvedAttribute (bool value) + { + Value = value; + } + } +} diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj index 843401413ca4..0c0212fa8398 100644 --- a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj +++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj @@ -71,6 +71,7 @@ + diff --git a/linker/Tests/Mono.Linker.Tests.Cases/TypeForwarding/MissingTargetReference.cs b/linker/Tests/Mono.Linker.Tests.Cases/TypeForwarding/MissingTargetReference.cs index 07f43ef3210a..5e8b115717cd 100644 --- a/linker/Tests/Mono.Linker.Tests.Cases/TypeForwarding/MissingTargetReference.cs +++ b/linker/Tests/Mono.Linker.Tests.Cases/TypeForwarding/MissingTargetReference.cs @@ -4,6 +4,7 @@ namespace Mono.Linker.Tests.Cases.TypeForwarding { + [SkipUnresolved (true)] [Define ("IL_ASSEMBLY_AVAILABLE")] [SetupCompileBefore ("TypeForwarderMissingReference.dll", new [] { "Dependencies/TypeForwarderMissingReference.il" })] [SetupLinkerAction ("link", "TypeForwarderMissingReference.dll")] diff --git a/linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs b/linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs index a5bf7f658d37..b776923cc6d3 100644 --- a/linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs +++ b/linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs @@ -66,6 +66,14 @@ public virtual void AddAssemblyAction (string action, string assembly) Append (assembly); } + public virtual void AddSkipUnresolved (bool skipUnresolved) + { + if (skipUnresolved) { + Append ("--skip-unresolved"); + Append ("true"); + } + } + public string [] ToArgs () { return _arguments.ToArray (); @@ -108,6 +116,8 @@ public virtual void ProcessOptions (TestCaseLinkerOptions options) if (!string.IsNullOrEmpty (options.LinkSymbols)) AddLinkSymbols (options.LinkSymbols); + AddSkipUnresolved (options.SkipUnresolved); + // Unity uses different argument format and needs to be able to translate to their format. In order to make that easier // we keep the information in flag + values format for as long as we can so that this information doesn't have to be parsed out of a single string foreach (var additionalArgument in options.AdditionalArguments) diff --git a/linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs b/linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs index 675a0641edce..916bc38d71bb 100644 --- a/linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs +++ b/linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs @@ -11,6 +11,7 @@ public class TestCaseLinkerOptions public bool IncludeBlacklistStep; public string KeepTypeForwarderOnlyAssemblies; public string LinkSymbols; + public bool SkipUnresolved; public List> AdditionalArguments = new List> (); } diff --git a/linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs index cc87f0bf81de..3bd1d531b38a 100644 --- a/linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs +++ b/linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs @@ -31,7 +31,8 @@ public virtual TestCaseLinkerOptions GetLinkerOptions () IncludeBlacklistStep = GetOptionAttributeValue (nameof (IncludeBlacklistStepAttribute), false), KeepTypeForwarderOnlyAssemblies = GetOptionAttributeValue (nameof (KeepTypeForwarderOnlyAssembliesAttribute), string.Empty), LinkSymbols = GetOptionAttributeValue (nameof (SetupLinkerLinkSymbolsAttribute), string.Empty), - CoreAssembliesAction = GetOptionAttributeValue (nameof (SetupLinkerCoreActionAttribute), null) + CoreAssembliesAction = GetOptionAttributeValue (nameof (SetupLinkerCoreActionAttribute), null), + SkipUnresolved = GetOptionAttributeValue (nameof (SkipUnresolvedAttribute), false) }; foreach (var assemblyAction in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (SetupLinkerActionAttribute)))