public Global Load() { if (global != null) throw new InvalidOperationException("CCILoader::Load() should be invoked only once"); var strongNameToInfo = new Dictionary<StrongAssemblyName, AssemblyInfo>(); var fileNameToStrongName = new Dictionary<string, StrongAssemblyName>(); // Entry for (referencor strong name, referencee strong name) for references know to be unresolvable var knownBad = new HashSet<string>(); // ---------------------------------------- // The assembly resolver invoked by CCI as needed // ---------------------------------------- CCI.Module.AssemblyReferenceResolver resolver = (target, source) => { var targetinfo = default(AssemblyInfo); var targetsn = StrongAssemblyNameFromCCIReference(target); if (strongNameToInfo.TryGetValue(targetsn, out targetinfo)) return targetinfo.Assembly; else { var sourceInfo = default(AssemblyInfo); var sourceFileName = "<unknown>"; var sourcesn = StrongAssemblyNameFromCCIAssembly(source.ContainingAssembly); if (strongNameToInfo.TryGetValue(sourcesn, out sourceInfo)) sourceFileName = sourceInfo.FileName; var key = "(" + sourcesn + "," + targetsn + ")"; if (!knownBad.Contains(key)) { knownBad.Add(key); log (new UnresolvableReferenceMessage (source.ContainingAssembly.StrongName, sourceFileName, target.StrongName)); } throw new ExitException(); // turns out CCI will happily swallow this exception and replay it later... } }; // ---------------------------------------- // Which assembly should we use for mscorlib? // ---------------------------------------- var mscorlibCanonicalName = default(string); foreach (var fileName in fileNames) { var canonicalFileName = CanonicalFileName(fileName); if (fileNameToStrongName.ContainsKey(canonicalFileName)) { log(new DuplicateAssemblyFileNameMessage(fileName, canonicalFileName)); throw new ExitException(); } fileNameToStrongName.Add(canonicalFileName, null); var baseName = Path.GetFileNameWithoutExtension(canonicalFileName); if (baseName.Equals("mscorlib", StringComparison.OrdinalIgnoreCase)) { if (mscorlibCanonicalName != null) { log(new DuplicateSpecialAssemblyMessage("mscorlib", mscorlibCanonicalName, canonicalFileName)); throw new ExitException(); } mscorlibCanonicalName = canonicalFileName; } } if (mscorlibCanonicalName == null) { log(new MissingSpecialAssemblyMessage("mscorlib")); throw new ExitException(); } // ---------------------------------------- // Initialize CCI, which will implicitly load mscorlib // ---------------------------------------- var frameworkDir = Path.GetDirectoryName(mscorlibCanonicalName); if (!Directory.Exists(frameworkDir)) { log(new UnloadableMSCorLibMessage(frameworkDir)); throw new ExitException(); } // These special CCI assemblies, and mscorlib, will be picked up from the framework directory CCI.SystemDataAssemblyLocation.Location = null; CCI.SystemXmlAssemblyLocation.Location = null; CCI.TargetPlatform.SetToV2(frameworkDir); // At this point we could "fixup" CCI's hard-wired system assembly references: // // foreach (var asmRefs in CCI.TargetPlatform.AssemblyReferenceFor.GetEnumerator()) // { // var asmRef = (CCI.AssemblyReference)asmRefs.Value; // asmRef.Location = <the right place>; // } // SystemAssemblyLocation.Location = <the right place>; // SystemXmlAssemblyLocation.Location = <the right place>; // // But so far that doesn't seem necessary CCI.SystemTypes.Initialize(false, true, resolver); // ---------------------------------------- // Account for mscorlib being loaded // ---------------------------------------- var mscorlib = CCI.SystemTypes.SystemAssembly; if (mscorlib == null || mscorlib.Directory == null) { log(new UnloadableMSCorLibMessage(frameworkDir)); throw new ExitException(); } var mscorlibName = StrongAssemblyNameFromCCIAssembly(mscorlib); fileNameToStrongName[mscorlibCanonicalName] = mscorlibName; strongNameToInfo.Add(mscorlibName, new AssemblyInfo { Assembly = mscorlib, FileName = mscorlibCanonicalName }); log(new LoadedAssemblyMessage(mscorlib.StrongName, mscorlibCanonicalName)); Void = ResolveCCIType(mscorlib, "System", "Void"); ValueType = ResolveCCIType(mscorlib, "System", "ValueType"); Enum = ResolveCCIType(mscorlib, "System", "Enum"); global = new Global(mscorlibName); // The global environment is now ready for use... // ---------------------------------------- // Load the remaining registered assemblies // ---------------------------------------- var pending = new List<string>(); foreach (var kv in fileNameToStrongName) { if (kv.Value == null) pending.Add(kv.Key); // else: must have been mscorlib, which we loaded above } foreach (var canonicalFileName in pending) { var assembly = CCI.AssemblyNode.GetAssembly(canonicalFileName, null, false, true, true); if (assembly == null) { log(new UnloadableAssemblyMessage(canonicalFileName)); throw new ExitException(); } var sn = StrongAssemblyNameFromCCIAssembly(assembly); var info = default(AssemblyInfo); if (strongNameToInfo.TryGetValue(sn, out info)) { log(new DuplicateAssemblyStrongNameMessage(canonicalFileName, sn.ToString(), info.FileName)); throw new ExitException(); } log(new LoadedAssemblyMessage(sn.ToString(), canonicalFileName)); fileNameToStrongName[canonicalFileName] = sn; strongNameToInfo.Add(sn, new AssemblyInfo { Assembly = assembly, FileName = canonicalFileName }); assembly.AssemblyReferenceResolution += resolver; } // ---------------------------------------- // Convert all assemblies. Since we visit all assemblies and types this will also check that // all assembly references resolved to valid assemblies. // ---------------------------------------- // We use the global environment for the first time here... var assemblies = new List<AssemblyDef>(); foreach (var kv in strongNameToInfo) { try { assemblies.Add(AssemblyDefFromCCIAssembly(kv.Value.Assembly)); log(new ResolvedAssemblyMessage(kv.Key.ToString(), kv.Value.FileName)); } catch (InvalidOperationException) { log(new UnresolvableAssemblyMessage(kv.Key.ToString(), kv.Value.FileName)); throw new ExitException(); } } global.AddAssemblies(assemblies); // ---------------------------------------- // Teardown CCI // ---------------------------------------- cciQualifiedTypeNameCache.Clear(); foreach (var kv in strongNameToInfo) kv.Value.Assembly.Dispose(); strongNameToInfo.Clear(); CCI.TargetPlatform.Clear(); return global; }