private (SourceGeneratorHostWrapper Wrapper, AppDomain Domain) CreateDomain(HostCollection collection) { (SourceGeneratorHostWrapper Wrapper, AppDomain Domain)hostEntry; Log.LogMessage($"Creating generation host ({collection.Entry.OwnerFile}, {string.Join(", ", collection.Entry.Analyzers)}, {Environment.OSVersion.Platform})"); var generatorLocations = SourceGenerators.Select(Path.GetFullPath).Select(Path.GetDirectoryName).Distinct(); var wrapperBasePath = Path.GetDirectoryName(new Uri(typeof(SourceGeneratorHostWrapper).Assembly.CodeBase).LocalPath); // We can create an app domain per OwnerFile and all Analyzers files // so that if those change, we can spin off another one, and still avoid // locking these assemblies. // // If the domain exists, keep it and continue generating content with it. var setup = new AppDomainSetup(); setup.ApplicationBase = wrapperBasePath; setup.ShadowCopyFiles = "true"; setup.ShadowCopyDirectories = string.Join(";", generatorLocations) + ";" + wrapperBasePath; setup.PrivateBinPath = setup.ShadowCopyDirectories; setup.ConfigurationFile = Path.Combine(wrapperBasePath, typeof(SourceGeneratorHostWrapper).Assembly.GetName().Name + ".dll.config"); // Loader optimization must not use MultiDomainHost, otherwise MSBuild assemblies may // be shared incorrectly when multiple versions are loaded in different domains. // The loader must specify SingleDomain, otherwise in contexts where devenv.exe is the // current process, the default optimization is "MultiDomain" and assemblies are // incorrectly reused. setup.LoaderOptimization = LoaderOptimization.SingleDomain; var domain = AppDomain.CreateDomain("Generators-" + Guid.NewGuid(), null, setup); Log.LogMessage($"[{Process.GetCurrentProcess().ProcessName}] Creating object {typeof(SourceGeneratorHostWrapper).Assembly.CodeBase} with {typeof(SourceGeneratorHostWrapper).FullName}. wrapperBasePath {wrapperBasePath} "); var newHost = domain.CreateInstanceFromAndUnwrap( typeof(SourceGeneratorHostWrapper).Assembly.CodeBase, typeof(SourceGeneratorHostWrapper).FullName ) as SourceGeneratorHostWrapper; var msbuildBasePath = Path.GetDirectoryName(new Uri(typeof(Microsoft.Build.Logging.ConsoleLogger).Assembly.CodeBase).LocalPath); newHost.MSBuildBasePath = msbuildBasePath; newHost.AdditionalAssemblies = AdditionalAssemblies; newHost.Initialize(); hostEntry = (newHost, domain); return(hostEntry); }
private HostCollection GetCollection() { var entry = new DomainEntry(this.BuildEngine4.ProjectFileOfTaskNode, Platform, SourceGenerators.Select(Path.GetFullPath).ToArray()); HostCollection collection = GetHost(entry); if (collection.IsInvalid) { Log.LogMessage("Discarding source generation host, generators files have been modified"); _domains.TryRemove(entry, out collection); UnloadHosts(collection); collection = GetHost(entry); } return(collection); }