@@ -29,31 +29,44 @@ public static IEnumerable<string> ResolveRuntimeDependenciesCore(
29
29
string [ ] applicationDependencies ,
30
30
string [ ] monoBclDirectories )
31
31
{
32
- var assembly = new AssemblyEntry ( entryPoint , GetAssemblyName ( entryPoint ) ) ;
32
+ var entryAssembly = new AssemblyEntry ( entryPoint , GetAssemblyName ( entryPoint ) ) ;
33
33
34
- var dependencies = applicationDependencies
35
- . Select ( a => new AssemblyEntry ( a , GetAssemblyName ( a ) ) )
36
- . ToArray ( ) ;
34
+ var dependencies = CreateAssemblyLookup ( applicationDependencies ) ;
37
35
38
- var bcl = monoBclDirectories
39
- . SelectMany ( d => Directory . EnumerateFiles ( d , "*.dll" ) . Select ( f => Path . Combine ( d , f ) ) )
40
- . Select ( a => new AssemblyEntry ( a , GetAssemblyName ( a ) ) )
41
- . ToArray ( ) ;
36
+ var bcl = CreateAssemblyLookup ( monoBclDirectories
37
+ . SelectMany ( d => Directory . EnumerateFiles ( d , "*.dll" ) . Select ( f => Path . Combine ( d , f ) ) ) ) ;
42
38
43
39
var assemblyResolutionContext = new AssemblyResolutionContext (
44
- assembly ,
40
+ entryAssembly ,
45
41
dependencies ,
46
42
bcl ) ;
47
43
48
44
assemblyResolutionContext . ResolveAssemblies ( ) ;
49
45
50
46
var paths = assemblyResolutionContext . Results . Select ( r => r . Path ) ;
51
47
return paths . Concat ( FindPdbs ( paths ) ) ;
48
+
49
+ static Dictionary < string , AssemblyEntry > CreateAssemblyLookup ( IEnumerable < string > assemblyPaths )
50
+ {
51
+ var dictionary = new Dictionary < string , AssemblyEntry > ( StringComparer . Ordinal ) ;
52
+ foreach ( var path in assemblyPaths )
53
+ {
54
+ var assemblyName = AssemblyName . GetAssemblyName ( path ) . Name ;
55
+ if ( dictionary . TryGetValue ( assemblyName , out var previous ) )
56
+ {
57
+ throw new InvalidOperationException ( $ "Multiple assemblies found with the same assembly name '{ assemblyName } ':" +
58
+ Environment . NewLine + string . Join ( Environment . NewLine , previous , path ) ) ;
59
+ }
60
+ dictionary [ assemblyName ] = new AssemblyEntry ( path , assemblyName ) ;
61
+ }
62
+
63
+ return dictionary ;
64
+ }
52
65
}
53
66
54
- private static string GetAssemblyName ( string entryPoint )
67
+ private static string GetAssemblyName ( string assemblyPath )
55
68
{
56
- return AssemblyName . GetAssemblyName ( entryPoint ) . Name ;
69
+ return AssemblyName . GetAssemblyName ( assemblyPath ) . Name ;
57
70
}
58
71
59
72
private static IEnumerable < string > FindPdbs ( IEnumerable < string > dllPaths )
@@ -66,26 +79,26 @@ private static IEnumerable<string> FindPdbs(IEnumerable<string> dllPaths)
66
79
public class AssemblyResolutionContext
67
80
{
68
81
public AssemblyResolutionContext (
69
- AssemblyEntry assembly ,
70
- AssemblyEntry [ ] dependencies ,
71
- AssemblyEntry [ ] bcl )
82
+ AssemblyEntry entryAssembly ,
83
+ Dictionary < string , AssemblyEntry > dependencies ,
84
+ Dictionary < string , AssemblyEntry > bcl )
72
85
{
73
- Assembly = assembly ;
86
+ EntryAssembly = entryAssembly ;
74
87
Dependencies = dependencies ;
75
88
Bcl = bcl ;
76
89
}
77
90
78
- public AssemblyEntry Assembly { get ; }
79
- public AssemblyEntry [ ] Dependencies { get ; }
80
- public AssemblyEntry [ ] Bcl { get ; }
91
+ public AssemblyEntry EntryAssembly { get ; }
92
+ public Dictionary < string , AssemblyEntry > Dependencies { get ; }
93
+ public Dictionary < string , AssemblyEntry > Bcl { get ; }
81
94
82
95
public IList < AssemblyEntry > Results { get ; } = new List < AssemblyEntry > ( ) ;
83
96
84
97
internal void ResolveAssemblies ( )
85
98
{
86
99
var visitedAssemblies = new HashSet < string > ( ) ;
87
100
var pendingAssemblies = new Stack < string > ( ) ;
88
- pendingAssemblies . Push ( Assembly . Name ) ;
101
+ pendingAssemblies . Push ( EntryAssembly . Name ) ;
89
102
ResolveAssembliesCore ( ) ;
90
103
91
104
void ResolveAssembliesCore ( )
@@ -96,8 +109,7 @@ void ResolveAssembliesCore()
96
109
{
97
110
// Not all references will be resolvable within the Mono BCL.
98
111
// Skipping unresolved assemblies here is equivalent to passing "--skip-unresolved true" to the Mono linker.
99
- var resolved = Resolve ( current ) ;
100
- if ( resolved != null )
112
+ if ( Resolve ( current ) is AssemblyEntry resolved )
101
113
{
102
114
Results . Add ( resolved ) ;
103
115
var references = GetAssemblyReferences ( resolved . Path ) ;
@@ -110,17 +122,22 @@ void ResolveAssembliesCore()
110
122
}
111
123
}
112
124
113
- AssemblyEntry Resolve ( string assemblyName )
125
+ AssemblyEntry ? Resolve ( string assemblyName )
114
126
{
115
- if ( Assembly . Name == assemblyName )
127
+ if ( EntryAssembly . Name == assemblyName )
116
128
{
117
- return Assembly ;
129
+ return EntryAssembly ;
118
130
}
119
131
120
132
// Resolution logic. For right now, we will prefer the mono BCL version of a given
121
133
// assembly if there is a candidate assembly and an equivalent mono assembly.
122
- return Bcl . FirstOrDefault ( c => c . Name == assemblyName ) ??
123
- Dependencies . FirstOrDefault ( c => c . Name == assemblyName ) ;
134
+ if ( Bcl . TryGetValue ( assemblyName , out var assembly ) ||
135
+ Dependencies . TryGetValue ( assemblyName , out assembly ) )
136
+ {
137
+ return assembly ;
138
+ }
139
+
140
+ return null ;
124
141
}
125
142
126
143
static IReadOnlyList < string > GetAssemblyReferences ( string assemblyPath )
@@ -157,16 +174,16 @@ static IReadOnlyList<string> GetAssemblyReferences(string assemblyPath)
157
174
}
158
175
159
176
[ DebuggerDisplay ( "{ToString(),nq}" ) ]
160
- public class AssemblyEntry
177
+ public readonly struct AssemblyEntry
161
178
{
162
179
public AssemblyEntry ( string path , string name )
163
180
{
164
181
Path = path ;
165
182
Name = name ;
166
183
}
167
184
168
- public string Path { get ; set ; }
169
- public string Name { get ; set ; }
185
+ public string Path { get ; }
186
+ public string Name { get ; }
170
187
171
188
public override string ToString ( ) => Name ;
172
189
}
0 commit comments