コード例 #1
0
        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);
        }
コード例 #2
0
        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);
        }