예제 #1
0
        private static CSharpCompilationOptions GetCompilationOptions(
            IWebHostEnvironment hostingEnvironment,
            DependencyContextCompilationOptions dependencyContextOptions)
        {
            var csharpCompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

            // Disable 1702 until roslyn turns this off by default
            csharpCompilationOptions = csharpCompilationOptions.WithSpecificDiagnosticOptions(
                new Dictionary <string, ReportDiagnostic>
            {
                { "CS1701", ReportDiagnostic.Suppress },   // Binding redirects
                { "CS1702", ReportDiagnostic.Suppress },
                { "CS1705", ReportDiagnostic.Suppress }
            });

            if (dependencyContextOptions.AllowUnsafe.HasValue)
            {
                csharpCompilationOptions = csharpCompilationOptions.WithAllowUnsafe(
                    dependencyContextOptions.AllowUnsafe.Value);
            }

            OptimizationLevel optimizationLevel;

            if (dependencyContextOptions.Optimize.HasValue)
            {
                optimizationLevel = dependencyContextOptions.Optimize.Value ?
                                    OptimizationLevel.Release :
                                    OptimizationLevel.Debug;
            }
            else
            {
                optimizationLevel = hostingEnvironment.IsDevelopment() ?
                                    OptimizationLevel.Debug :
                                    OptimizationLevel.Release;
            }
            csharpCompilationOptions = csharpCompilationOptions.WithOptimizationLevel(optimizationLevel);

            if (dependencyContextOptions.WarningsAsErrors.HasValue)
            {
                var reportDiagnostic = dependencyContextOptions.WarningsAsErrors.Value ?
                                       ReportDiagnostic.Error :
                                       ReportDiagnostic.Default;
                csharpCompilationOptions = csharpCompilationOptions.WithGeneralDiagnosticOption(reportDiagnostic);
            }

            return(csharpCompilationOptions);
        }
        public static CSharpCompilationOptions CreateCompilationOptions(this ProjectFileInfo projectFileInfo)
        {
            var compilationOptions = new CSharpCompilationOptions(projectFileInfo.OutputKind);

            compilationOptions = compilationOptions.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default)
                                 .WithSpecificDiagnosticOptions(projectFileInfo.GetDiagnosticOptions())
                                 .WithOverflowChecks(projectFileInfo.CheckForOverflowUnderflow);

            if (projectFileInfo.AllowUnsafeCode)
            {
                compilationOptions = compilationOptions.WithAllowUnsafe(true);
            }

            if (projectFileInfo.TreatWarningsAsErrors)
            {
                compilationOptions = compilationOptions.WithGeneralDiagnosticOption(ReportDiagnostic.Error);
            }

            if (projectFileInfo.NullableContextOptions != compilationOptions.NullableContextOptions)
            {
                compilationOptions = compilationOptions.WithNullableContextOptions(projectFileInfo.NullableContextOptions);
            }

            if (projectFileInfo.SignAssembly && !string.IsNullOrEmpty(projectFileInfo.AssemblyOriginatorKeyFile))
            {
                var keyFile = Path.Combine(projectFileInfo.Directory, projectFileInfo.AssemblyOriginatorKeyFile);
                compilationOptions = compilationOptions.WithStrongNameProvider(new DesktopStrongNameProvider())
                                     .WithCryptoKeyFile(keyFile);
            }

            if (!string.IsNullOrWhiteSpace(projectFileInfo.DocumentationFile))
            {
                compilationOptions = compilationOptions.WithXmlReferenceResolver(XmlFileResolver.Default);
            }

            return(compilationOptions);
        }
예제 #3
0
        /// <summary>
        /// Compiles an embedded resource into an executable and writes it to disk in the same
        /// directory as the executing assembly.
        /// </summary>
        /// <param name="sourceResourcePath">
        /// The relative resource path, as it must be formatted for a pack URI.
        /// </param>
        /// <param name="absOutputPath">
        /// The absolute path
        /// </param>
        private string CompileExe(string sourceResourcePath, string absOutputPath)
        {
            m_logger.Info("Compiling internal service: {0} to output {1}.", sourceResourcePath, absOutputPath);
            string scriptContents = string.Empty;

            using (var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(sourceResourcePath))
            {
                using (TextReader tsr = new StreamReader(resourceStream))
                {
                    scriptContents = tsr.ReadToEnd();
                }
            }

            if (scriptContents == null || scriptContents.Length == 0)
            {
                m_logger.Warn("When compiling internal service {0}, failed to load source code.", sourceResourcePath);
                return(string.Empty);
            }

            // The sentinel service is special. It's the only that's going to watch us.
            // So, we need to code our process name into its source before compilation.
            if (sourceResourcePath.IndexOf("Sentinel", StringComparison.OrdinalIgnoreCase) != -1)
            {
                scriptContents = scriptContents.Replace("TARGET_APPLICATION_NAME", Process.GetCurrentProcess().ProcessName);
            }

            HashSet <string> allRefs = new HashSet <string>();

            var dd      = typeof(Enumerable).GetTypeInfo().Assembly.Location;
            var coreDir = Directory.GetParent(dd);

            List <MetadataReference> references = new List <MetadataReference>
            {
                // Here we get the path to the mscorlib and private mscorlib
                // libraries that are required for compilation to succeed.
                //MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
                MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)
            };

            var referencedAssemblies = RecursivelyGetReferencedAssemblies(Assembly.GetEntryAssembly());

            foreach (var referencedAssembly in referencedAssemblies)
            {
                var mref = MetadataReference.CreateFromFile(referencedAssembly.Location);

                if (referencedAssembly.FullName.Contains("System.Runtime.Extension"))
                {
                    // Have to do this to avoid collisions with duplicate type
                    // definitions between private mscorlib and this assembly.
                    // XXX TODO - Needs to be solved in a better way?
                    mref = mref.WithAliases(new List <string>(new[] { "CorPrivate" }));
                }

                if (!allRefs.Contains(mref.Display))
                {
                    references.Add(mref);
                    allRefs.Add(mref.Display);
                }
            }

            // Setup syntax parse options for C#.
            CSharpParseOptions parseOptions = CSharpParseOptions.Default;

            parseOptions = parseOptions.WithLanguageVersion(LanguageVersion.CSharp6);
            parseOptions = parseOptions.WithDocumentationMode(DocumentationMode.None);
            parseOptions = parseOptions.WithKind(SourceCodeKind.Regular);

            // Parse text into syntax tree.
            SyntaxTree jobSyntaxTree = CSharpSyntaxTree.ParseText(scriptContents, parseOptions);

            // Initialize compilation arguments for the build script we're about
            // to compile.
            var op = new CSharpCompilationOptions(OutputKind.ConsoleApplication);

            op = op.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
            op = op.WithGeneralDiagnosticOption(ReportDiagnostic.Warn);

            // Initialize the compilation with our options, references and the
            // already parsed syntax tree of the build script.
            CSharpCompilation compilation = CSharpCompilation.Create(
                Path.GetFileNameWithoutExtension(absOutputPath),
                syntaxTrees: new[] { jobSyntaxTree },
                references: references,
                options: op);

            // Compile and emit new assembly into memory.
            using (var ms = new MemoryStream())
            {
                EmitResult result = compilation.Emit(ms);

                if (result.Success)
                {
                    File.WriteAllBytes(absOutputPath, ms.ToArray());
                    m_logger.Info("Generated service assembly {0} for service {1}.", absOutputPath, Path.GetFileNameWithoutExtension(absOutputPath));
                    return(absOutputPath);
                }
                else
                {
                    // Compilation failed.
                    m_logger.Error("Failed to generate service assembly for service {0}.", Path.GetFileNameWithoutExtension(absOutputPath));

                    foreach (var diag in result.Diagnostics)
                    {
                        m_logger.Error(diag.GetMessage());
                    }
                }
            }

            return(string.Empty);
        }
예제 #4
0
        public HostBuildData Create(HostBuildOptions options)
        {
            var parseOptions = new CSharpParseOptions(languageVersion: LanguageVersion.CSharp6, documentationMode: DocumentationMode.Parse);
            var compilationOptions = new CSharpCompilationOptions(
                OutputKind.ConsoleApplication,
                xmlReferenceResolver: new XmlFileResolver(options.ProjectDirectory),
                sourceReferenceResolver: new SourceFileResolver(ImmutableArray<string>.Empty, options.ProjectDirectory),
                metadataReferenceResolver: new AssemblyReferenceResolver(
                    new MetadataFileReferenceResolver(ImmutableArray<string>.Empty, options.ProjectDirectory),
                    MetadataFileReferenceProvider.Default),
                strongNameProvider: new DesktopStrongNameProvider(ImmutableArray.Create(options.ProjectDirectory, options.OutputDirectory)),
                assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default);
            var warnings = new List<KeyValuePair<string, ReportDiagnostic>>(options.Warnings);

            if (options.OutputKind.HasValue)
            {
                var kind = options.OutputKind.Value;
                compilationOptions = compilationOptions.WithOutputKind(kind);
                if (compilationOptions.Platform == Platform.AnyCpu32BitPreferred &&
                    (kind == OutputKind.DynamicallyLinkedLibrary || kind == OutputKind.NetModule || kind == OutputKind.WindowsRuntimeMetadata))
                {
                    compilationOptions = compilationOptions.WithPlatform(Platform.AnyCpu);
                }
            }

            if (!string.IsNullOrEmpty(options.DefineConstants))
            {
                IEnumerable<Diagnostic> diagnostics;
                parseOptions = parseOptions.WithPreprocessorSymbols(CSharpCommandLineParser.ParseConditionalCompilationSymbols(options.DefineConstants, out diagnostics));
            }

            if (options.DocumentationFile != null)
            {
                parseOptions = parseOptions.WithDocumentationMode(!string.IsNullOrEmpty(options.DocumentationFile) ? DocumentationMode.Diagnose : DocumentationMode.Parse);
            }

            if (options.LanguageVersion != null)
            {
                var languageVersion = CompilationOptionsConversion.GetLanguageVersion(options.LanguageVersion);
                if (languageVersion.HasValue)
                {
                    parseOptions = parseOptions.WithLanguageVersion(languageVersion.Value);
                }
            }

            if (!string.IsNullOrEmpty(options.PlatformWith32BitPreference))
            {
                Platform platform;
                if (Enum.TryParse<Platform>(options.PlatformWith32BitPreference, true, out platform))
                {
                    if (platform == Platform.AnyCpu &&
                        compilationOptions.OutputKind != OutputKind.DynamicallyLinkedLibrary &&
                        compilationOptions.OutputKind != OutputKind.NetModule &&
                        compilationOptions.OutputKind != OutputKind.WindowsRuntimeMetadata)
                    {
                        platform = Platform.AnyCpu32BitPreferred;
                    }

                    compilationOptions = compilationOptions.WithPlatform(platform);
                }
            }

            if (options.AllowUnsafeBlocks.HasValue)
            {
                compilationOptions = compilationOptions.WithAllowUnsafe(options.AllowUnsafeBlocks.Value);
            }

            if (options.CheckForOverflowUnderflow.HasValue)
            {
                compilationOptions = compilationOptions.WithOverflowChecks(options.CheckForOverflowUnderflow.Value);
            }

            if (options.DelaySign != null)
            {
                bool delaySignExplicitlySet = options.DelaySign.Item1;
                bool delaySign = options.DelaySign.Item2;
                compilationOptions = compilationOptions.WithDelaySign(delaySignExplicitlySet ? delaySign : (bool?)null);
            }

            if (!string.IsNullOrEmpty(options.ApplicationConfiguration))
            {
                var appConfigPath = FileUtilities.ResolveRelativePath(options.ApplicationConfiguration, options.ProjectDirectory);
                try
                {
                    using (var appConfigStream = PortableShim.FileStream.Create(appConfigPath, PortableShim.FileMode.Open, PortableShim.FileAccess.Read))
                    {
                        compilationOptions = compilationOptions.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.LoadFromXml(appConfigStream));
                    }
                }
                catch (Exception)
                {
                }
            }

            if (!string.IsNullOrEmpty(options.KeyContainer))
            {
                compilationOptions = compilationOptions.WithCryptoKeyContainer(options.KeyContainer);
            }

            if (!string.IsNullOrEmpty(options.KeyFile))
            {
                var fullPath = FileUtilities.ResolveRelativePath(options.KeyFile, options.ProjectDirectory);
                compilationOptions = compilationOptions.WithCryptoKeyFile(fullPath);
            }

            if (!string.IsNullOrEmpty(options.MainEntryPoint))
            {
                compilationOptions = compilationOptions.WithMainTypeName(options.MainEntryPoint);
            }

            if (!string.IsNullOrEmpty(options.ModuleAssemblyName))
            {
                compilationOptions = compilationOptions.WithModuleName(options.ModuleAssemblyName);
            }

            if (options.Optimize.HasValue)
            {
                compilationOptions = compilationOptions.WithOptimizationLevel(options.Optimize.Value ? OptimizationLevel.Release : OptimizationLevel.Debug);
            }

            if (!string.IsNullOrEmpty(options.Platform))
            {
                Platform plat;
                if (Enum.TryParse<Platform>(options.Platform, ignoreCase: true, result: out plat))
                {
                    compilationOptions = compilationOptions.WithPlatform(plat);
                }
            }

            // Get options from the ruleset file, if any.
            if (!string.IsNullOrEmpty(options.RuleSetFile))
            {
                var fullPath = FileUtilities.ResolveRelativePath(options.RuleSetFile, options.ProjectDirectory);

                Dictionary<string, ReportDiagnostic> specificDiagnosticOptions;
                var generalDiagnosticOption = RuleSet.GetDiagnosticOptionsFromRulesetFile(fullPath, out specificDiagnosticOptions);
                compilationOptions = compilationOptions.WithGeneralDiagnosticOption(generalDiagnosticOption);
                warnings.AddRange(specificDiagnosticOptions);
            }

            if (options.WarningsAsErrors.HasValue)
            {
                compilationOptions = compilationOptions.WithGeneralDiagnosticOption(options.WarningsAsErrors.Value ? ReportDiagnostic.Error : ReportDiagnostic.Default);
            }

            if (options.WarningLevel.HasValue)
            {
                compilationOptions = compilationOptions.WithWarningLevel(options.WarningLevel.Value);
            }

            compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(warnings);
            return new HostBuildData(
                parseOptions,
                compilationOptions);
        }
예제 #5
0
        /// <summary>
        /// This method attempts to load the build script at the given location,
        /// compile return the exported AbstractBuildTask from it. The script
        /// file must inherit from AbstractBuildTask.
        /// </summary>
        /// <param name="taskScriptPath">
        /// The path to the build script to run.
        /// </param>
        /// <returns>
        /// In the event of successful discovery, read and compilation of the
        /// script at the given path, a list of all exported AbstractBuildTasks
        /// from the compiled assembly is returned.
        /// </returns>
        private static List <AbstractBuildTask> LoadTaskFromScript(string taskScriptPath)
        {
            WriteTitleToConsole("Loading & Parsing Build Script");

            // Exhaustively verify that the file exists, is readable and is not
            // an empty file.
            Debug.Assert(!string.IsNullOrEmpty(taskScriptPath) && !string.IsNullOrWhiteSpace(taskScriptPath), "Build task script path is null, empty or whitespace.");

            if (string.IsNullOrEmpty(taskScriptPath) || string.IsNullOrWhiteSpace(taskScriptPath))
            {
                throw new ArgumentException("Build task script path is null, empty or whitespace.", nameof(taskScriptPath));
            }

            Debug.Assert(File.Exists(taskScriptPath), "Build task script path points to non-existent file.");

            if (!File.Exists(taskScriptPath))
            {
                throw new ArgumentException("Build task script path points to non-existent file.");
            }

            Console.WriteLine(string.Format("Reading all text from file {0}", taskScriptPath));

            var scriptContents = File.ReadAllText(taskScriptPath);

            Debug.Assert(!string.IsNullOrEmpty(scriptContents) && !string.IsNullOrWhiteSpace(scriptContents), "Build task script contents are null, empty or whitespace.");

            if (string.IsNullOrEmpty(scriptContents) || string.IsNullOrWhiteSpace(scriptContents))
            {
                throw new ArgumentException("Build task script contents are null, empty or whitespace.", nameof(taskScriptPath));
            }

            // Setup syntax parse options for C#.
            CSharpParseOptions parseOptions = CSharpParseOptions.Default;

            parseOptions = parseOptions.WithLanguageVersion(LanguageVersion.CSharp6);
            parseOptions = parseOptions.WithDocumentationMode(DocumentationMode.None);
            parseOptions = parseOptions.WithKind(SourceCodeKind.Regular);

            // Parse text into syntax tree.
            SyntaxTree jobSyntaxTree = CSharpSyntaxTree.ParseText(scriptContents, parseOptions);

            // Generate a random file name for the assembly we're about to produce.
            string generatedAssemblyName = Path.GetRandomFileName();

            // Get the directory of a core assembly. We need this directory to
            // build out our platform specific reference to mscorlib. mscorlib
            // and the private mscorlib must be supplied as references for
            // compilation to succeed. Of these two assemblies, only the private
            // mscorlib is discovered via enumerataing assemblies referenced by
            // this executing binary.
            var dd      = typeof(Enumerable).GetTypeInfo().Assembly.Location;
            var coreDir = Directory.GetParent(dd);

            HashSet <string> allRefs = new HashSet <string>();

            List <MetadataReference> references = new List <MetadataReference>
            {
                // Here we get the path to the mscorlib and private mscorlib
                // libraries that are required for compilation to succeed.
                MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
                MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)
            };

            // Enumerate all assemblies referenced by this executing assembly
            // and provide them as references to the build script we're about to
            // compile.
            var referencedAssemblies = RecursivelyGetReferencedAssemblies(Assembly.GetEntryAssembly());

            foreach (var referencedAssembly in referencedAssemblies)
            {
                var mref = MetadataReference.CreateFromFile(referencedAssembly.Location);

                if (referencedAssembly.FullName.Contains("System.Runtime.Extension"))
                {
                    // Have to do this to avoid collisions with duplicate type
                    // definitions between private mscorlib and this assembly.
                    // XXX TODO - Needs to be solved in a better way?
                    mref = mref.WithAliases(new List <string>(new[] { "CorPrivate" }));
                }

                if (!allRefs.Contains(mref.Display))
                {
                    references.Add(mref);
                    allRefs.Add(mref.Display);
                }

                /* For debugging, to try to list explicit platform compat. Flaky.
                 * try
                 * {
                 *  var customAttributes = loadedAssembly.GetCustomAttributes();
                 *  var attribute = customAttributes.OfType<TargetFrameworkAttribute>().First();
                 *
                 *  Console.WriteLine(attribute.FrameworkName);
                 *  Console.WriteLine(attribute.FrameworkDisplayName);
                 * }
                 * catch{}
                 */
            }

            // Initialize compilation arguments for the build script we're about
            // to compile.
            var op = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

            op = op.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
            op = op.WithGeneralDiagnosticOption(ReportDiagnostic.Warn);

            // Initialize the compilation with our options, references and the
            // already parsed syntax tree of the build script.
            CSharpCompilation compilation = CSharpCompilation.Create(
                generatedAssemblyName,
                syntaxTrees: new[] { jobSyntaxTree },
                references: references,
                options: op);

            // Compile and emit new assembly into memory.
            var        ms     = new MemoryStream();
            EmitResult result = compilation.Emit(ms);

            if (result.Success)
            {
                // Store the in-memory assembly until this program exits.
                GeneratedAssemblies.Add(ms);

                // Get an Assembly structure from the data in memory.
                ms.Seek(0, SeekOrigin.Begin);
                AssemblyLoadContext loadCtx  = AssemblyLoadContext.Default;
                Assembly            assembly = loadCtx.LoadFromStream(ms);

                // Enumerate types exported from the assembly. Presently not used.
                var exportedTypes = assembly.ExportedTypes;
                foreach (var xp in exportedTypes)
                {
                    Console.WriteLine(string.Format("Build script exports type: {0}", xp.Name));
                }

                // Filter exported types so we only pull types extending from AbstractBuildTask.
                var filteredExports = exportedTypes.Where(x => x.Name != typeof(AbstractBuildTask).Name);
                Console.WriteLine(string.Format("Number of exported build objects: {0}", filteredExports.Count()));

                // Ensure that we have at least one exported build task.
                Debug.Assert(filteredExports.Count() > 0, "Script either does not export any AbstractBuildTask objects. Build scripts should export one or more AbstractBuildTask objects.");
                if (filteredExports.Count() <= 0)
                {
                    throw new ArgumentException("Script either does not export any AbstractBuildTask objects. Build scripts should export one or more AbstractBuildTask objects.", nameof(taskScriptPath));
                }

                var filteredExportsList             = filteredExports.ToList();
                List <AbstractBuildTask> buildTasks = new List <AbstractBuildTask>();

                foreach (var entry in filteredExportsList)
                {
                    AbstractBuildTask typedExport = (AbstractBuildTask)Activator.CreateInstance(entry, new[] { taskScriptPath.ConvertToHostOsPath() });
                    buildTasks.Add(typedExport);
                }

                return(buildTasks);
            }
            else
            {
                ms.Dispose();

                Console.WriteLine(string.Format("Failed to compile build script: {0}.", taskScriptPath));

                IEnumerable <Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                                                                             diagnostic.IsWarningAsError ||
                                                                             diagnostic.Severity == DiagnosticSeverity.Error);

                foreach (Diagnostic diagnostic in failures)
                {
                    Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
                }

                CleanExit(ExitCodes.ScriptCompilationFailure);
            }

            Console.WriteLine("null");

            return(null);
        }