37 readonly List<string> libpath =
new List<string>();
39 Version coreLibVersion;
41 internal enum WarningId
45 InvalidLibDirectoryOption = 3,
46 InvalidLibDirectoryEnvironment = 4,
50 internal delegate
void WarningEvent(WarningId warning,
string message,
string[] parameters);
51 internal event WarningEvent Warning;
53 private void EmitWarning(WarningId warning,
string message, params
string[] parameters)
57 Warning(warning, message, parameters);
61 Console.Error.WriteLine(
"Warning: " + message, parameters);
65 internal void Init(Universe universe,
bool nostdlib, IList<string> references, IList<string> userLibPaths)
67 this.universe = universe;
72 libpath.Add(Environment.CurrentDirectory);
74 if (nostdlib ==
false)
75 libpath.Add(
System.
Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory());
77 foreach (var str
in userLibPaths)
78 AddLibraryPaths(str,
true);
80 AddLibraryPaths(Environment.GetEnvironmentVariable(
"LIB") ??
"",
false);
84 coreLibVersion = LoadCoreLib(references).GetName().Version;
88 coreLibVersion = universe.Load(universe.CoreLibName).GetName().Version;
92 universe.AssemblyResolve += AssemblyResolve;
94 universe.AssemblyResolve += LegacyAssemblyResolve;
98 internal Assembly LoadFile(
string path)
103 using (RawModule module = universe.OpenRawModule(path))
105 if (coreLibVersion !=
null)
108 foreach (AssemblyName asmref
in module.GetReferencedAssemblies())
110 if (asmref.Name == universe.CoreLibName && asmref.Version > coreLibVersion)
112 Console.Error.WriteLine(
"Error: unable to load assembly '{0}' as it depends on a higher version of mscorlib than the one currently loaded", path);
117 Assembly
asm = universe.LoadAssembly(module);
118 if (
asm.Location != module.Location && CanonicalizePath(
asm.Location) != CanonicalizePath(module.Location))
120 EmitWarning(WarningId.LocationIgnored,
"assembly \"{0}\" is ignored as previously loaded assembly \"{1}\" has the same identity \"{2}\"", path,
asm.Location,
asm.FullName);
125 catch (IOException x)
129 catch (UnauthorizedAccessException x)
137 Console.Error.WriteLine(
"Error: unable to load assembly '{0}'" + Environment.NewLine +
" ({1})", path, ex);
142 private static string CanonicalizePath(
string path)
146 System.IO.FileInfo fi =
new System.IO.FileInfo(path);
147 if (fi.DirectoryName ==
null)
149 return path.Length > 1 && path[1] ==
':' ? path.ToUpper() : path;
151 string dir = CanonicalizePath(fi.DirectoryName);
152 string name = fi.Name;
155 string[] arr =
System.IO.Directory.GetFileSystemEntries(dir, name);
161 catch (
System.UnauthorizedAccessException)
164 catch (
System.IO.IOException)
167 return System.IO.Path.Combine(dir, name);
169 catch (
System.UnauthorizedAccessException)
172 catch (
System.IO.IOException)
175 catch (
System.Security.SecurityException)
178 catch (
System.NotSupportedException)
184 internal Assembly LoadWithPartialName(
string name)
186 foreach (
string path
in FindAssemblyPath(name +
".dll"))
187 return LoadFile(path);
192 internal bool ResolveReference(Dictionary<string, Assembly> cache,
ref Assembly[] references,
string reference)
194 string[] files =
new string[0];
197 string path = Path.GetDirectoryName(reference);
198 files = Directory.GetFiles(path ==
"" ?
"." : path, Path.GetFileName(reference));
200 catch (ArgumentException)
206 if (files.Length == 0)
209 cache.TryGetValue(reference, out
asm);
212 foreach (
string found
in FindAssemblyPath(reference))
214 asm = LoadFile(found);
215 cache.Add(reference,
asm);
223 ArrayAppend(
ref references,
asm);
227 foreach (
string file
in files)
230 if (!cache.TryGetValue(file, out
asm))
232 asm = LoadFile(file);
234 ArrayAppend(
ref references,
asm);
240 private static void ArrayAppend<T>(
ref T[] array, T element)
244 array =
new T[] { element };
248 array =
ArrayUtil.Concat(array, element);
256 foreach (var
asm in universe.GetAssemblies())
257 if (Match(
asm.GetName(), name))
260 if (args.RequestingAssembly !=
null)
262 return universe.CreateMissingAssembly(args.Name);
272 return LegacyLoad(
new AssemblyName(args.Name), args.RequestingAssembly);
275 internal Assembly LegacyLoad(AssemblyName name, Assembly requestingAssembly)
277 foreach (Assembly
asm in universe.GetAssemblies())
278 if (Match(
asm.GetName(), name))
281 foreach (
string file
in FindAssemblyPath(name.Name +
".dll"))
282 if (Match(AssemblyName.GetAssemblyName(file), name))
283 return LoadFile(file);
285 if (requestingAssembly !=
null)
287 var path = Path.Combine(Path.GetDirectoryName(requestingAssembly.Location), name.Name +
".dll");
288 if (File.Exists(path) && Match(AssemblyName.GetAssemblyName(path), name))
289 return LoadFile(path);
293 return universe.CreateMissingAssembly(name.FullName);
295 Console.Error.WriteLine(
"Error: unable to find assembly '{0}'", name.FullName);
296 if (requestingAssembly !=
null)
297 Console.Error.WriteLine(
" (a dependency of '{0}')", requestingAssembly.FullName);
300 throw new InvalidOperationException();
303 private bool Match(AssemblyName assemblyDef, AssemblyName assemblyRef)
305 return assemblyRef.Name == assemblyDef.Name;
308 private void AddLibraryPaths(
string str,
bool option)
310 foreach (
string dir
in str.Split(Path.PathSeparator))
312 if (Directory.Exists(dir))
320 EmitWarning(WarningId.InvalidLibDirectoryOption,
"directory \"{0}\" specified in -lib option is not valid", dir);
324 EmitWarning(WarningId.InvalidLibDirectoryEnvironment,
"directory \"{0}\" specified in LIB environment is not valid", dir);
330 Assembly LoadCoreLib(IList<string> references)
332 if (references !=
null)
334 foreach (var r
in references)
338 if (AssemblyName.GetAssemblyName(r).Name == universe.CoreLibName)
350 foreach (var coreLib
in FindAssemblyPath(universe.CoreLibName +
".dll"))
351 return LoadFile(coreLib);
353 Console.Error.WriteLine($
"Error: unable to find '{universe.CoreLibName}.dll'.");
358 IEnumerable<string> FindAssemblyPath(
string file)
360 if (Path.IsPathRooted(file))
362 if (File.Exists(file))
369 foreach (
string dir
in libpath)
371 var path = Path.Combine(dir, file);
372 if (File.Exists(path))
376 path = Path.Combine(dir, file +
".dll");
377 if (File.Exists(path))
379 EmitWarning(WarningId.LegacySearchRule,
"found assembly \"{0}\" using legacy search rule, please append '.dll' to the reference", file);