private EmitOptions GetEmitOptions(out bool emitPdb) { var emitOptions = new EmitOptions(); var usePortablePdbString = Environment.GetEnvironmentVariable(EnvironmentNames.PortablePdb); // Use portable pdbs if explicitly specified or the platform doesn't support pdb generation var usePortablePdb = string.Equals(usePortablePdbString, "true", StringComparison.OrdinalIgnoreCase) || string.Equals(usePortablePdbString, "1", StringComparison.OrdinalIgnoreCase); if (usePortablePdb) { Logger.TraceInformation("Using portable pdb format"); // Emit the portable pdb format if explicitly specified. // TODO: Make a decision about when we use the portable pdb by default. // On mono < 4.2 Emitting the portable PDB just hangs for some odd reason. emitPdb = true; return(emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb)); } // Otherwise, emit the regular pdb format if the platfom supports it emitPdb = _supportsPdbGeneration.Value; return(emitOptions); }
public static CompilerResults Compile(CompilerParameters args, string[] files) { var name = Path.GetFileNameWithoutExtension(args.OutputAssembly); var pdbPath = Path.ChangeExtension(args.OutputAssembly, "pdb"); var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithOptimizationLevel(args.IncludeDebugInformation ? OptimizationLevel.Debug : OptimizationLevel.Release) .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default); var parseOptions = new CSharpParseOptions(LanguageVersion.Latest); var emitOptions = new EmitOptions(); if (Type.GetType("Mono.Runtime") != null) { emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); } var refs = args.ReferencedAssemblies.Cast <string>().Select(s => MetadataReference.CreateFromFile(s)); var src = files.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, f, Encoding.UTF8)); var comp = CSharpCompilation.Create(name, src, refs, options); EmitResult results; using (var peStream = File.OpenWrite(args.OutputAssembly)) using (var pdbStream = args.IncludeDebugInformation ? File.OpenWrite(pdbPath) : null) { results = comp.Emit(peStream, pdbStream, options: emitOptions); } var cRes = new CompilerResults(args.TempFiles); foreach (var d in results.Diagnostics) { if (d.Severity != DiagnosticSeverity.Error) { continue; } var loc = d.Location.GetLineSpan(); var pos = loc.StartLinePosition; cRes.Errors.Add(new CompilerError(loc.Path ?? "", pos.Line, pos.Character, d.Id, d.GetMessage())); } return(cRes); }
public static CompilerErrorCollection Compile(string name, string outputPath, string[] references, string[] files, bool includePdb) { var pdbPath = Path.ChangeExtension(outputPath, "pdb"); var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithOptimizationLevel(OptimizationLevel.Debug) // currently no way to specify debug vs release. We still want pdb files with release mode for bug reports .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default); var parseOptions = new CSharpParseOptions(LanguageVersion.Latest); var emitOptions = new EmitOptions(); if (Type.GetType("Mono.Runtime") != null) { emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); } var refs = references.Select(s => MetadataReference.CreateFromFile(s)); var src = files.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, f, Encoding.UTF8)); var comp = CSharpCompilation.Create(name, src, refs, options); EmitResult results; using (var peStream = File.OpenWrite(outputPath)) using (var pdbStream = includePdb ? File.OpenWrite(pdbPath) : null) { results = comp.Emit(peStream, pdbStream, options: emitOptions); } var errors = new CompilerErrorCollection(); foreach (var d in results.Diagnostics.Where(d => d.Severity >= DiagnosticSeverity.Warning)) { var loc = d.Location.GetLineSpan(); errors.Add(new CompilerError { ErrorNumber = d.Id, IsWarning = d.Severity == DiagnosticSeverity.Warning, ErrorText = d.GetMessage(), FileName = loc.Path ?? "", Line = loc.StartLinePosition.Line, Column = loc.StartLinePosition.Character }); } return(errors); }
public override Tuple <Type, CompilationData> CompileType(TypeContext context) { var sourceCode = GetCodeCompileUnit(context); var assemblyName = GetAssemblyName(context); (new PermissionSet(PermissionState.Unrestricted)).Assert(); var tempDir = GetTemporaryDirectory(); var sourceCodeFile = Path.Combine(tempDir, String.Format("{0}.{1}", assemblyName, SourceFileExtension)); File.WriteAllText(sourceCodeFile, sourceCode); var references = GetAllReferences(context); var compilation = GetEmptyCompilation(assemblyName) .AddSyntaxTrees( GetSyntaxTree(sourceCode, sourceCodeFile)) .AddReferences(GetMetadataReferences(references)); compilation = compilation .WithOptions( CreateOptions(context) .WithOutputKind(OutputKind.DynamicallyLinkedLibrary) .WithPlatform(Platform.AnyCpu) .WithSourceReferenceResolver(new RazorEngineSourceReferenceResolver(sourceCodeFile))); var assemblyFile = Path.Combine(tempDir, String.Format("{0}.dll", assemblyName)); var assemblyPdbFile = Path.Combine(tempDir, String.Format("{0}.pdb", assemblyName)); var compilationData = new CompilationData(sourceCode, tempDir); using (var assemblyStream = File.Open(assemblyFile, FileMode.Create, FileAccess.ReadWrite)) using (var pdbStream = File.Open(assemblyPdbFile, FileMode.Create, FileAccess.ReadWrite)) { var opts = new EmitOptions() .WithPdbFilePath(assemblyPdbFile); var pdbStreamHelper = pdbStream; if (IsMono()) { opts = opts.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); } EmitResult result = null; if (Debugger.IsAttached) { result = compilation.Emit(assemblyStream, pdbStreamHelper, options: opts); } else { result = compilation.Emit(assemblyStream); } //var result = compilation.Emit(assemblyStream, pdbStreamHelper, options: opts); //var result = compilation.Emit(assemblyStream); if (!result.Success) { var errors = result.Diagnostics.Select(diag => { var lineSpan = diag.Location.GetLineSpan(); return(new Templating.RazorEngineCompilerError( string.Format("{0}", diag.GetMessage()), lineSpan.Path, lineSpan.StartLinePosition.Line, lineSpan.StartLinePosition.Character, diag.Id, diag.Severity != DiagnosticSeverity.Error)); }); throw new Templating.TemplateCompilationException(errors, compilationData, context.TemplateContent); } } // load file and return loaded type. Assembly assembly; if (DisableTempFileLocking) { assembly = File.Exists(assemblyPdbFile) ? Assembly.Load(File.ReadAllBytes(assemblyFile), File.ReadAllBytes(assemblyPdbFile)) : Assembly.Load(File.ReadAllBytes(assemblyFile)); } else { assembly = Assembly.LoadFrom(assemblyFile); } var type = assembly.GetType(DynamicTemplateNamespace + "." + context.ClassName); return(Tuple.Create(type, compilationData)); }
/// <summary> /// Generates and compiles an assembly for the provided syntax. /// </summary> /// <param name="generatedSyntax"> /// The generated code. /// </param> /// <param name="assemblyName"> /// The name for the generated assembly. /// </param> /// <param name="emitDebugSymbols"> /// Whether or not to emit debug symbols for the generated assembly. /// </param> /// <returns> /// The raw assembly. /// </returns> /// <exception cref="CodeGenerationException"> /// An error occurred generating code. /// </exception> private Assembly CompileAssembly(GeneratedSyntax generatedSyntax, string assemblyName, bool emitDebugSymbols) { // Add the generated code attribute. var code = CodeGeneratorCommon.AddGeneratedCodeAttribute(generatedSyntax); // Reference everything which can be referenced. var assemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(asm => !asm.IsDynamic && !string.IsNullOrWhiteSpace(asm.Location)) .Select(asm => MetadataReference.CreateFromFile(asm.Location)) .Cast <MetadataReference>() .ToArray(); // Generate the code. var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); #if NETSTANDARD2_0 // CoreFX bug https://github.com/dotnet/corefx/issues/5540 // to workaround it, we are calling internal WithTopLevelBinderFlags(BinderFlags.IgnoreCorLibraryDuplicatedTypes) // TODO: this API will be public in the future releases of Roslyn. // This work is tracked in https://github.com/dotnet/roslyn/issues/5855 // Once it's public, we should replace the internal reflection API call by the public one. var method = typeof(CSharpCompilationOptions).GetMethod("WithTopLevelBinderFlags", BindingFlags.NonPublic | BindingFlags.Instance); // we need to pass BinderFlags.IgnoreCorLibraryDuplicatedTypes, but it's an internal class // http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/Binder/BinderFlags.cs,00f268571bb66b73 options = (CSharpCompilationOptions)method.Invoke(options, new object[] { 1u << 26 }); #endif string source = null; if (this.logger.IsEnabled(LogLevel.Debug)) { source = CodeGeneratorCommon.GenerateSourceCode(code); // Compile the code and load the generated assembly. this.logger.Debug( ErrorCode.CodeGenSourceGenerated, "Generating assembly {0} with source:\n{1}", assemblyName, source); } var compilation = CSharpCompilation.Create(assemblyName) .AddSyntaxTrees(code.SyntaxTree) .AddReferences(assemblies) .WithOptions(options); using (var outputStream = new MemoryStream()) { var emitOptions = new EmitOptions() .WithEmitMetadataOnly(false) .WithIncludePrivateMembers(true); if (emitDebugSymbols) { emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.Embedded); } var compilationResult = compilation.Emit(outputStream, options: emitOptions); if (!compilationResult.Success) { source = source ?? CodeGeneratorCommon.GenerateSourceCode(code); var errors = string.Join("\n", compilationResult.Diagnostics.Select(_ => _.ToString())); this.logger.Warn( ErrorCode.CodeGenCompilationFailed, "Compilation of assembly {0} failed with errors:\n{1}\nGenerated Source Code:\n{2}", assemblyName, errors, source); throw new CodeGenerationException(errors); } this.logger.Debug( ErrorCode.CodeGenCompilationSucceeded, "Compilation of assembly {0} succeeded.", assemblyName); return(Assembly.Load(outputStream.ToArray())); } }
CodeCompilerResult CompileFileInternal( CodeCompilerArguments arguments, TextWriter log, CancellationToken token) { CSharpCommandLineArguments args = null; if (arguments.AdditionalArguments != null) { var splitArgs = CommandLineParser.SplitCommandLineIntoArguments(arguments.AdditionalArguments, false); if (splitArgs.Any()) { args = CSharpCommandLineParser.Default.Parse(splitArgs, arguments.TempDirectory, null, null); } } var references = new List <MetadataReference> (); foreach (var assemblyReference in AssemblyResolver.GetResolvedReferences(runtime, arguments.AssemblyReferences)) { references.Add(MetadataReference.CreateFromFile(assemblyReference)); } var parseOptions = args?.ParseOptions ?? new CSharpParseOptions(); if (arguments.LangVersion != null) { if (LanguageVersionFacts.TryParse(arguments.LangVersion, out var langVersion)) { parseOptions = parseOptions.WithLanguageVersion(langVersion); } else { throw new System.Exception($"Unknown value '{arguments.LangVersion}' for langversion"); } } else { // need to update this when updating referenced roslyn binaries CSharpLangVersionHelper.GetBestSupportedLangVersion(runtime, CSharpLangVersion.v9_0); } var syntaxTrees = new List <SyntaxTree> (); foreach (var sourceFile in arguments.SourceFiles) { using var stream = File.OpenRead(sourceFile); var sourceText = SourceText.From(stream, Encoding.UTF8, canBeEmbedded: true); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(sourceText, parseOptions, cancellationToken: token, path: sourceFile); syntaxTrees.Add(syntaxTree); } var compilationOptions = (args?.CompilationOptions ?? new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .WithOutputKind(OutputKind.DynamicallyLinkedLibrary); var compilation = CSharpCompilation.Create( "GeneratedTextTransformation", syntaxTrees, references, compilationOptions ); EmitOptions emitOptions = args?.EmitOptions ?? new EmitOptions(); if (arguments.Debug) { var embeddedTexts = syntaxTrees.Select(st => EmbeddedText.FromSource(st.FilePath, st.GetText())).ToList(); emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.Embedded); } using var fs = File.OpenWrite(arguments.OutputPath); EmitResult result = compilation.Emit(fs, options: emitOptions, cancellationToken: token); if (result.Success) { return(new CodeCompilerResult { Output = new List <string> (), Success = true, Errors = new List <CodeCompilerError> () }); } var failures = result.Diagnostics.Where(x => x.IsWarningAsError || x.Severity == DiagnosticSeverity.Error); var errors = failures.Select(x => { var location = x.Location.GetMappedLineSpan(); var startLinePosition = location.StartLinePosition; var endLinePosition = location.EndLinePosition; return(new CodeCompilerError { Message = x.GetMessage(), Column = startLinePosition.Character, Line = startLinePosition.Line, EndLine = endLinePosition.Line, EndColumn = endLinePosition.Character, IsError = x.Severity == DiagnosticSeverity.Error, Origin = location.Path }); }).ToList(); return(new CodeCompilerResult { Success = false, Output = new List <string> (), Errors = errors }); }
/// <summary> /// Compiles <paramref name="code"/> and creates script. /// </summary> /// <param name="options">Compilation options.</param> /// <param name="code">Code to be compiled.</param> /// <param name="builder">Assembly builder.</param> /// <param name="previousSubmissions">Enumeration of scripts that were evaluated within current context. New submission may reference them.</param> /// <returns>New script representing the compiled code.</returns> public static Script Create(Context.ScriptOptions options, string code, PhpCompilationFactory builder, IEnumerable <Script> previousSubmissions) { // use the language version of the requesting context var languageVersion = options.LanguageVersion; var shortOpenTags = false; var language = options.Context.TargetPhpLanguage; if (language != null) { shortOpenTags = language.ShortOpenTag; languageVersion ??= language.LanguageVersion; } // unique in-memory assembly name var name = builder.GetNewSubmissionName(); // submission do not have the opening "<?php" script tag: var kind = options.IsSubmission ? SourceCodeKind.Script : SourceCodeKind.Regular; if (kind == SourceCodeKind.Script && options.EmitDebugInformation) { // since submission do not have the opening "<?php" tag, // add a comment with the opening tag, so source code editors don't get confused and colorize the code properly: code = $"#<?php\n{code}"; } // parse the source code var tree = PhpSyntaxTree.ParseCode( SourceText.From(code, Encoding.UTF8, SourceHashAlgorithm.Sha256), new PhpParseOptions( kind: kind, languageVersion: languageVersion, shortOpenTags: shortOpenTags), PhpParseOptions.Default, options.IsSubmission ? BuildSubmissionFileName(options.Location.Path, name.Name) : options.Location.Path ); var diagnostics = tree.Diagnostics; if (!HasErrors(diagnostics)) { // TODO: collect required types from {tree}, remember as a script dependencies // TODO: perform class autoload (now before compilation, and then always before invocation) // list of scripts that were eval'ed in the context already, // our compilation may depend on them var dependingSubmissions = previousSubmissions.Where(s => !s.Image.IsDefaultOrEmpty); IEnumerable <MetadataReference> metadatareferences = dependingSubmissions.Select(s => MetadataReference.CreateFromImage(s.Image)); if (options.AdditionalReferences != null) { // add additional script references metadatareferences = metadatareferences.Concat(options.AdditionalReferences.Select(r => MetadataReference.CreateFromFile(r))); } // create the compilation object // TODO: add conditionally declared types into the compilation tables var compilation = (PhpCompilation)builder.CoreCompilation .WithLangVersion(languageVersion) .WithAssemblyName(name.Name) .AddSyntaxTrees(tree) .AddReferences(metadatareferences); var emitOptions = new EmitOptions(); var embeddedTexts = default(IEnumerable <EmbeddedText>); if (options.EmitDebugInformation) { compilation = compilation.WithPhpOptions(compilation.Options.WithOptimizationLevel(OptimizationLevel.Debug).WithDebugPlusMode(true)); emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); if (options.IsSubmission) { embeddedTexts = new[] { EmbeddedText.FromSource(tree.FilePath, tree.GetText()) }; } } else { compilation = compilation.WithPhpOptions(compilation.Options.WithOptimizationLevel(OptimizationLevel.Release)); } diagnostics = compilation.GetDeclarationDiagnostics(); if (!HasErrors(diagnostics)) { var peStream = new MemoryStream(); var pdbStream = options.EmitDebugInformation ? new MemoryStream() : null; var result = compilation.Emit(peStream, pdbStream: pdbStream, options: emitOptions, embeddedTexts: embeddedTexts ); if (result.Success) { return(new Script(name, peStream, pdbStream, builder, previousSubmissions)); } else { diagnostics = result.Diagnostics; } } } // return(CreateInvalid(diagnostics)); }
private CompilerResults CompileWithRoslyn(List <string> filenames, List <string> sources, ICollection <Assembly> referencedAssemblies) { #if ROSLYN CompilerResults cr; CSharpCompilationOptions options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); EmitOptions emitOptions = new EmitOptions(); if (includeDebugInformation) { // Embedded option doesn't seem to work // Explanation of options: https://github.com/dotnet/designs/blob/master/accepted/diagnostics/debugging-with-symbols-and-sources.md emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); } else { emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.Embedded); } if (optimizeCode) { options = options.WithOptimizationLevel(OptimizationLevel.Release); } // If running on the Mono VM, disable all warnings in the generated // code because these are treated as errors by the Mono compiler. if (runningOnMono) { options = options.WithWarningLevel(0); } List <MetadataReference> references = new List <MetadataReference>(); foreach (Assembly assembly in referencedAssemblies) { try { references.Add(MetadataReference.CreateFromFile(assembly.Location)); } catch (NotSupportedException) { // do nothing - this assembly does not have a location e.g. it is in memory } catch (Exception e) { Console.WriteLine("Warning, could not add location for assembly: " + assembly); Console.WriteLine(e); } } // we must only add references to assemblies that are actually referenced by the code -- not all the assemblies in memory during model compilation (that could be a much larger set) SyntaxTree[] trees; if (!writeSourceFiles) { // Note: Without source files, the debugger cannot step into generated code, even if a pdb is generated. // Theoretically, it should be possible to embed the source into the pdb. trees = sources.Select(s => CSharpSyntaxTree.ParseText(s, encoding: Encoding.UTF8)).ToArray(); } else { trees = filenames.Select(fn => CSharpSyntaxTree.ParseText(File.ReadAllText(fn), null, fn, Encoding.UTF8)).ToArray(); } string targetAssemblyPath = ""; string pdbPath = ""; string targetAssemblyName; if (!generateInMemory) { targetAssemblyPath = Path.ChangeExtension(filenames[0], ".dll"); try { if (File.Exists(targetAssemblyPath)) { File.Delete(targetAssemblyPath); } } catch { for (int i = 0; ; i++) { targetAssemblyPath = Path.ChangeExtension(Path.ChangeExtension(filenames[0], null) + DateTime.Now.Millisecond, ".dll"); try { if (File.Exists(targetAssemblyPath)) { File.Delete(targetAssemblyPath); } break; } catch { } } } targetAssemblyName = Path.GetFileNameWithoutExtension(targetAssemblyPath); pdbPath = Path.ChangeExtension(targetAssemblyPath, ".pdb"); emitOptions = emitOptions.WithPdbFilePath(pdbPath); } else { targetAssemblyName = Guid.NewGuid().ToString(); // Empty names are not allowed } Compilation compilation = CSharpCompilation.Create(targetAssemblyName, trees, references, options); Assembly resultAssembly = null; EmitResult result; using (Stream assemblyStream = generateInMemory ? (Stream) new MemoryStream() : File.Create(targetAssemblyPath)) { using (Stream pdbStream = generateInMemory ? (Stream) new MemoryStream() : File.Create(pdbPath)) { if (emitOptions.DebugInformationFormat == DebugInformationFormat.Embedded) { result = compilation.Emit(assemblyStream, options: emitOptions); } else { result = compilation.Emit(assemblyStream, pdbStream, options: emitOptions); } if (result.Success) { // TODO: allow compiled assemblies to be unloaded assemblyStream.Seek(0, SeekOrigin.Begin); var asmBin = new BinaryReader(assemblyStream).ReadBytes((int)assemblyStream.Length); if (emitOptions.DebugInformationFormat == DebugInformationFormat.Embedded) { resultAssembly = Assembly.Load(asmBin); } else { pdbStream.Seek(0, SeekOrigin.Begin); var pdbBin = new BinaryReader(pdbStream).ReadBytes((int)pdbStream.Length); resultAssembly = Assembly.Load(asmBin, pdbBin); } } } } cr = new CompilerResults(resultAssembly, result.Success, result.Diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Select(d => d.ToString()).ToList()); return(cr); #else throw new NotSupportedException("This assembly was compiled without Roslyn support. To use Roslyn, recompile with the ROSLYN compiler flag."); #endif }
private EmitOptions GetEmitOptions(out bool emitPdb) { var emitOptions = new EmitOptions(); var usePortablePdbString = Environment.GetEnvironmentVariable(EnvironmentNames.PortablePdb); // Use portable pdbs if explicitly specified or the platform doesn't support pdb generation var usePortablePdb = string.Equals(usePortablePdbString, "true", StringComparison.OrdinalIgnoreCase) || string.Equals(usePortablePdbString, "1", StringComparison.OrdinalIgnoreCase); if (usePortablePdb) { Logger.TraceInformation("Using portable pdb format"); // Emit the portable pdb format if explicitly specified. // TODO: Make a decision about when we use the portable pdb by default. // On mono < 4.2 Emitting the portable PDB just hangs for some odd reason. emitPdb = true; return emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); } // Otherwise, emit the regular pdb format if the platfom supports it emitPdb = _supportsPdbGeneration.Value; return emitOptions; }
public bool Compile( CompilerProvider compiler, string assname, bool debug, IReadOnlyCollection <string> files, out ImmutableArray <Diagnostic> diagnostics, out byte[] rawassembly, out byte[] rawsymbols) { rawassembly = null; rawsymbols = null; var success = true; var trees = files.Select(f => GetOrAddFile(f)).ToList(); foreach (var x in trees) { success &= IsSuccess(x.Diagnostics); } if (!success) { diagnostics = trees.SelectMany(x => x.Diagnostics).ToImmutableArray(); return(false); } var compilation = compiler.CreateCompilation(assname, trees, debug); var analysis = compilation.GetDiagnostics(); if (IsSuccess(analysis)) { var peStream = new MemoryStream(); var pdbStream = debug ? new MemoryStream() : null; var emitOptions = new EmitOptions(); if (debug) { emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); } var result = compilation.Emit(peStream, pdbStream: pdbStream, options: emitOptions); diagnostics = result.Diagnostics; if (result.Success) { rawassembly = peStream.ToArray(); rawsymbols = pdbStream?.ToArray(); return(true); } else { return(false); } } else { diagnostics = analysis; return(false); } }
public static CompilerResults CompileScript(string scriptSetup, string scriptSource, string outputDllFile) #endif { var source = @"# pragma warning disable 0168 // variable declared but not used. # pragma warning disable 0219 // variable assigned but not used. # pragma warning disable 0414 // private field assigned but not used. {using} namespace HomeGenie.Automation.Scripting { [Serializable] public class ScriptingInstance : ScriptingHost { private void RunCode(string PROGRAM_OPTIONS_STRING) { ////////////////////////////////////////////////////////////////// // NOTE: user code start line is 16 *** please add new code after this method, do not alter start line! *** {source} ////////////////////////////////////////////////////////////////// } #pragma warning disable 0162 private bool SetupCode() { ////////////////////////////////////////////////////////////////// // NOTE: user code start line is ??? *** please add new code after this method, do not alter start line! *** {setup} ////////////////////////////////////////////////////////////////// return false; } #pragma warning restore 0162 private HomeGenie.Automation.MethodRunResult Run(string PROGRAM_OPTIONS_STRING) { Exception ex = null; try { RunCode(PROGRAM_OPTIONS_STRING); } catch (Exception e) { ex = e; } return new HomeGenie.Automation.MethodRunResult(){ Exception = ex, ReturnValue = null }; } private HomeGenie.Automation.MethodRunResult Setup() { Exception ex = null; bool retval = false; try { retval = SetupCode(); } catch (Exception e) { ex = e; } return new HomeGenie.Automation.MethodRunResult(){ Exception = ex, ReturnValue = retval }; } public ScriptingHost hg { get { return (ScriptingHost)this; } } } }"; var usingNs = String.Join(" ", Includes.Select(x => String.Format("using {0};" + Environment.NewLine, x))); source = source .Replace("{using}", usingNs) .Replace("{source}", scriptSource) .Replace("{setup}", scriptSetup); #if NETCOREAPP var dotNetCoreDir = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location); var homeGenieDir = Path.GetDirectoryName(typeof(HomeGenieService).GetTypeInfo().Assembly.Location); var compilation = CSharpCompilation.Create("a") .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences( MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Enum).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Queryable).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Uri).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(HttpListener).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(DynamicObject).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Runtime.dll")), MetadataReference.CreateFromFile(Assembly.Load("netstandard").Location), MetadataReference.CreateFromFile(Assembly.Load("mscorlib").Location), MetadataReference.CreateFromFile(typeof(Thread).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(Stopwatch).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Windows.dll")), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Threading.Thread.dll")), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Collections.dll")), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Net.dll")), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Net.Primitives.dll")), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Net.NameResolution.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "HomeGenie.dll")), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.dll")), MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.Core.dll")), MetadataReference.CreateFromFile(typeof(CSharpArgumentInfo).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "MIG.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, Path.Combine("lib", "mig", "CM19Lib.dll"))), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "LiteDB.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "NLog.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Newtonsoft.Json.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "SerialPortLib.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "NetClientLib.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "UPnP.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "MQTTnet.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Raspberry.IO.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Raspberry.IO.Components.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Raspberry.IO.GeneralPurpose.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Raspberry.IO.InterIntegratedCircuit.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Raspberry.IO.SerialPeripheralInterface.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Raspberry.System.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Innovative.Geometry.Angle.dll")), MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Innovative.SolarCalculator.dll")) ) .AddSyntaxTrees(CSharpSyntaxTree.ParseText(source)); var assemblyPdbFile = outputDllFile + ".pdb"; using var assemblyStream = File.Open(outputDllFile, FileMode.Create, FileAccess.ReadWrite); using var pdbStream = File.Open(assemblyPdbFile, FileMode.Create, FileAccess.ReadWrite); var opts = new EmitOptions() .WithPdbFilePath(assemblyPdbFile); var pdbStreamHelper = pdbStream; if (Environment.OSVersion.Platform == PlatformID.Unix) { opts = opts.WithDebugInformationFormat(DebugInformationFormat.PortablePdb); } var result = compilation.Emit(assemblyStream, pdbStreamHelper, options: opts); if (result.Success) { // TODO: } else { // TODO: } return(result); #else var providerOptions = new Dictionary <string, string> { //{ "CompilerVersion", "v4.0" } }; var provider = new CSharpCodeProvider(providerOptions); var compilerParams = new CompilerParameters { GenerateInMemory = false, GenerateExecutable = false, IncludeDebugInformation = true, TreatWarningsAsErrors = false, OutputAssembly = outputDllFile // *** Useful for debugging //,TempFiles = new TempFileCollection {KeepFiles = true} }; // Mono runtime 2/3 compatibility fix // TODO: this may not be required anymore var relocateSystemAsm = false; var type = Type.GetType("Mono.Runtime"); if (type != null) { MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); if (displayName != null) { int major; if (Int32.TryParse(displayName.Invoke(null, null).ToString().Substring(0, 1), out major) && major > 2) { relocateSystemAsm = true; } } } if (!relocateSystemAsm) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { var assemblyName = assembly.GetName(); switch (assemblyName.Name.ToLower()) { case "system": compilerParams.ReferencedAssemblies.Add(assembly.Location); break; case "system.core": compilerParams.ReferencedAssemblies.Add(assembly.Location); break; case "microsoft.csharp": compilerParams.ReferencedAssemblies.Add(assembly.Location); break; } } } else { compilerParams.ReferencedAssemblies.Add("System.dll"); compilerParams.ReferencedAssemblies.Add("System.Core.dll"); compilerParams.ReferencedAssemblies.Add("Microsoft.CSharp.dll"); } compilerParams.ReferencedAssemblies.Add("HomeGenie.exe"); compilerParams.ReferencedAssemblies.Add("MIG.dll"); compilerParams.ReferencedAssemblies.Add(Path.Combine("lib", "mig", "CM19Lib.dll")); compilerParams.ReferencedAssemblies.Add("LiteDB.dll"); compilerParams.ReferencedAssemblies.Add("NLog.dll"); compilerParams.ReferencedAssemblies.Add("Newtonsoft.Json.dll"); compilerParams.ReferencedAssemblies.Add("SerialPortLib.dll"); compilerParams.ReferencedAssemblies.Add("NetClientLib.dll"); compilerParams.ReferencedAssemblies.Add("UPnP.dll"); compilerParams.ReferencedAssemblies.Add("MQTTnet.dll"); //if (Raspberry.Board.Current.IsRaspberryPi) { compilerParams.ReferencedAssemblies.Add("Raspberry.IO.dll"); compilerParams.ReferencedAssemblies.Add("Raspberry.IO.Components.dll"); compilerParams.ReferencedAssemblies.Add("Raspberry.IO.GeneralPurpose.dll"); compilerParams.ReferencedAssemblies.Add("Raspberry.IO.InterIntegratedCircuit.dll"); compilerParams.ReferencedAssemblies.Add("Raspberry.IO.SerialPeripheralInterface.dll"); compilerParams.ReferencedAssemblies.Add("Raspberry.System.dll"); } compilerParams.ReferencedAssemblies.Add(Path.Combine("Innovative.Geometry.Angle.dll")); compilerParams.ReferencedAssemblies.Add(Path.Combine("Innovative.SolarCalculator.dll")); // compile and generate script assembly return(provider.CompileAssemblyFromSource(compilerParams, source)); #endif }