public static List <string> GetPreprocessorSymbols(CompilerOptions flags) { var preprocessorSymbols = new List <string>(); if (flags.HasFlag(CompilerOptions.UseDebug)) { preprocessorSymbols.Add("DEBUG"); } if (flags.HasFlag(CompilerOptions.Optimize)) { preprocessorSymbols.Add("OPT"); } if (flags.HasFlag(CompilerOptions.UseRoslyn)) { preprocessorSymbols.Add("ROSLYN"); preprocessorSymbols.Add("CS60"); preprocessorSymbols.Add("CS70"); preprocessorSymbols.Add("CS71"); preprocessorSymbols.Add("CS72"); preprocessorSymbols.Add("CS73"); preprocessorSymbols.Add("VB11"); preprocessorSymbols.Add("VB14"); preprocessorSymbols.Add("VB15"); } else if (flags.HasFlag(CompilerOptions.UseMcs)) { preprocessorSymbols.Add("MCS"); } else { preprocessorSymbols.Add("LEGACY_CSC"); preprocessorSymbols.Add("LEGACY_VBC"); } return(preprocessorSymbols); }
public void CheckedUnchecked([ValueSource("defaultOptions")] CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslyn) && cscOptions.HasFlag(CompilerOptions.Optimize)) { Assert.Ignore("Roslyn opt replaces locals with stack slots, resulting in S_* variable names."); } Run(cscOptions: cscOptions); }
public async Task StringInterpolation([ValueSource(nameof(roslynOnlyWithNet40Options))] CompilerOptions cscOptions) { if (!cscOptions.HasFlag(CompilerOptions.TargetNet40) && cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) { Assert.Ignore("DefaultInterpolatedStringHandler is not yet supported!"); return; } await Run(cscOptions : cscOptions); }
public ExpressionClosureResolver(LambdaExpression lambda, ModuleBuilder module, bool dynamic, CompilerOptions options) { lambda = (LambdaExpression) new LambdaPreparer().Visit(new RuntimeVariablesInliner().Visit(lambda)); if (!dynamic) { lambda = (LambdaExpression) new ExpressionPrivateMembersAccessor().Visit(new ExpressionAnonymousTypeReplacer(module).Visit(lambda)); } constantsBuilder = options.HasFlag(CompilerOptions.CreateDynamicClosure) ? new DynamicClosureBuilder(module) : (IClosureBuilder) new StaticClosureBuilder(); closureBuilder = options.HasFlag(CompilerOptions.CreateDynamicClosure) ? new DynamicClosureBuilder(module) : (IClosureBuilder) new StaticClosureBuilder(); parsedLambda = new ExpressionClosureBuilder(lambda, closureBuilder, constantsBuilder).Build(dynamic); }
void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { var ilFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".il"; var csFile = Path.Combine(TestCasePath, testName + ".cs"); if (!File.Exists(ilFile)) { // re-create .il file if necessary CompilerResults output = null; try { string outputFile = Path.ChangeExtension(ilFile, cscOptions.HasFlag(CompilerOptions.Library) ? ".dll" : ".exe"); output = Tester.CompileCSharp(csFile, cscOptions, outputFile); Tester.Disassemble(output.PathToAssembly, ilFile, asmOptions); } finally { if (output != null) { output.TempFiles.Delete(); } } } var executable = Tester.AssembleIL(ilFile, asmOptions); var decompiled = Tester.DecompileCSharp(executable, decompilerSettings ?? Tester.GetSettings(cscOptions)); CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray()); }
void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { var csFile = Path.Combine(TestCasePath, testName + ".cs"); var exeFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".exe"; if (cscOptions.HasFlag(CompilerOptions.Library)) { exeFile = Path.ChangeExtension(exeFile, ".dll"); } // 1. Compile CompilerResults output = null; try { output = Tester.CompileCSharp(csFile, cscOptions, exeFile); } finally { if (output != null) { output.TempFiles.Delete(); } } // 2. Decompile var decompiled = Tester.DecompileCSharp(exeFile, decompilerSettings ?? Tester.GetSettings(cscOptions)); // 3. Compile CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray()); }
internal static DecompilerSettings GetSettings(CompilerOptions cscOptions) { if ((cscOptions & CompilerOptions.UseRoslynMask) != 0) { var langVersion = (cscOptions & CompilerOptions.UseRoslynMask) switch { CompilerOptions.UseRoslyn1_3_2 => CSharp.LanguageVersion.CSharp6, CompilerOptions.UseRoslyn2_10_0 => CSharp.LanguageVersion.CSharp7_3, CompilerOptions.UseRoslyn3_11_0 => CSharp.LanguageVersion.CSharp9_0, _ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp10_0, }; return(new DecompilerSettings(langVersion) { // Never use file-scoped namespaces FileScopedNamespaces = false }); } else { var settings = new DecompilerSettings(CSharp.LanguageVersion.CSharp5); if ((cscOptions & CompilerOptions.UseMcsMask) != 0) { // we don't recompile with mcs but with roslyn, so we can use ref locals settings.UseRefLocalsForAccurateOrderOfEvaluation = true; } return(settings); } }
void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None) { var ilFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".il"; var csFile = Path.Combine(TestCasePath, testName + ".cs"); if (!File.Exists(ilFile)) { // re-create .il file if necessary CompilerResults output = null; try { output = Tester.CompileCSharp(csFile, cscOptions | CompilerOptions.Library); Tester.Disassemble(output.PathToAssembly, ilFile, asmOptions); } finally { if (output != null) { output.TempFiles.Delete(); } } } var executable = Tester.AssembleIL(ilFile, asmOptions | AssemblerOptions.Library); var decompiled = Tester.DecompileCSharp(executable); CodeAssert.FilesAreEqual(csFile, decompiled, cscOptions.HasFlag(CompilerOptions.UseRoslyn) ? null : new[] { "LEGACY_CSC" }); }
public async Task IndexRangeTest([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) { Assert.Ignore("See https://github.com/icsharpcode/ILSpy/issues/2540"); } await RunForLibrary(cscOptions : cscOptions); }
public async Task MiniJSON([ValueSource(nameof(defaultOptions))] CompilerOptions options) { if (options.HasFlag(CompilerOptions.UseMcs2_6_4)) { Assert.Ignore("Decompiler bug with mono!"); } await RunCS(options : options); }
public void YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions options) { if (options.HasFlag(CompilerOptions.UseMcs)) { Assert.Ignore("Decompiler bug with mono!"); } RunCS(options: options); }
public void UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions options) { if (options.HasFlag(CompilerOptions.UseMcs2_6_4)) { Assert.Ignore("Decompiler bug with mono!"); } RunCS(options: options); }
public void IndexRangeTest([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) { Assert.Ignore("See https://github.com/icsharpcode/ILSpy/issues/2540"); } RunForLibrary(cscOptions: cscOptions); }
public void MiniJSON([ValueSource("defaultOptions")] CompilerOptions options) { if (options.HasFlag(CompilerOptions.UseMcs)) { Assert.Ignore("Decompiler bug with mono!"); } RunCS(options: options); }
internal static DecompilerSettings GetSettings(CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslyn)) { if (cscOptions.HasFlag(CompilerOptions.Preview)) { return(new DecompilerSettings(CSharp.LanguageVersion.Latest)); } else { return(new DecompilerSettings(CSharp.LanguageVersion.CSharp8_0)); } } else { return(new DecompilerSettings(CSharp.LanguageVersion.CSharp5)); } }
public async Task CustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) { // Test C# 11 generic attributes cscOptions |= CompilerOptions.Preview; } await RunForLibrary(cscOptions : cscOptions); }
public static List <string> GetPreprocessorSymbols(CompilerOptions flags) { var preprocessorSymbols = new List <string>(); if (flags.HasFlag(CompilerOptions.UseDebug)) { preprocessorSymbols.Add("DEBUG"); } if (flags.HasFlag(CompilerOptions.Optimize)) { preprocessorSymbols.Add("OPT"); } if (flags.HasFlag(CompilerOptions.ReferenceCore)) { preprocessorSymbols.Add("NETCORE"); } if ((flags & CompilerOptions.UseRoslynMask) != 0) { preprocessorSymbols.Add("ROSLYN"); preprocessorSymbols.Add("CS60"); preprocessorSymbols.Add("VB11"); preprocessorSymbols.Add("VB14"); if (flags.HasFlag(CompilerOptions.UseRoslyn2_10_0) || flags.HasFlag(CompilerOptions.UseRoslynLatest)) { preprocessorSymbols.Add("ROSLYN2"); preprocessorSymbols.Add("CS70"); preprocessorSymbols.Add("CS71"); preprocessorSymbols.Add("CS72"); preprocessorSymbols.Add("VB15"); } if (flags.HasFlag(CompilerOptions.UseRoslynLatest)) { preprocessorSymbols.Add("ROSLYN3"); preprocessorSymbols.Add("CS73"); preprocessorSymbols.Add("CS80"); preprocessorSymbols.Add("VB16"); if (flags.HasFlag(CompilerOptions.Preview)) { preprocessorSymbols.Add("CS90"); } } } else if (flags.HasFlag(CompilerOptions.UseMcs)) { preprocessorSymbols.Add("MCS"); } else { preprocessorSymbols.Add("LEGACY_CSC"); preprocessorSymbols.Add("LEGACY_VBC"); } return(preprocessorSymbols); }
public static CompiledFunction Compile( ControlFlowGraph cfg, OperandType[] argTypes, OperandType retType, CompilerOptions options) { CompilerContext cctx = new(cfg, argTypes, retType, options); if (options.HasFlag(CompilerOptions.Optimize)) { Logger.StartPass(PassName.TailMerge); TailMerge.RunPass(cctx); Logger.EndPass(PassName.TailMerge, cfg); } if (options.HasFlag(CompilerOptions.SsaForm)) { Logger.StartPass(PassName.Dominance); Dominance.FindDominators(cfg); Dominance.FindDominanceFrontiers(cfg); Logger.EndPass(PassName.Dominance); Logger.StartPass(PassName.SsaConstruction); Ssa.Construct(cfg); Logger.EndPass(PassName.SsaConstruction, cfg); } else { Logger.StartPass(PassName.RegisterToLocal); RegisterToLocal.Rename(cfg); Logger.EndPass(PassName.RegisterToLocal, cfg); } return(CodeGenerator.Generate(cctx)); }
DecompilerSettings GetSettings(CompilerOptions options) { if (!options.HasFlag(CompilerOptions.UseRoslyn)) { return(new DecompilerSettings { StringInterpolation = false }); } return(new DecompilerSettings()); }
public async Task TupleTests([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) { Assert.Ignore("DefaultInterpolatedStringHandler is not yet supported!"); return; } await RunForLibrary(cscOptions : cscOptions); }
public static List <string> GetPreprocessorSymbols(CompilerOptions flags) { var preprocessorSymbols = new List <string>(); if (flags.HasFlag(CompilerOptions.UseDebug)) { preprocessorSymbols.Add("DEBUG"); } if (flags.HasFlag(CompilerOptions.Optimize)) { preprocessorSymbols.Add("OPT"); } if (flags.HasFlag(CompilerOptions.UseRoslyn)) { preprocessorSymbols.Add("ROSLYN"); } else { preprocessorSymbols.Add("LEGACY_CSC"); } return(preprocessorSymbols); }
internal static DecompilerSettings GetSettings(CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslyn)) { if (cscOptions.HasFlag(CompilerOptions.Preview)) { return(new DecompilerSettings(CSharp.LanguageVersion.Latest)); } else { return(new DecompilerSettings(CSharp.LanguageVersion.CSharp8_0)); } } else { var settings = new DecompilerSettings(CSharp.LanguageVersion.CSharp5); if (cscOptions.HasFlag(CompilerOptions.UseMcs)) { // we don't recompile with mcs but with roslyn, so we can use ref locals settings.UseRefLocalsForAccurateOrderOfEvaluation = true; } return(settings); } }
void Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) { var vbFile = Path.Combine(TestCasePath, testName + ".vb"); var csFile = Path.Combine(TestCasePath, testName + ".cs"); var exeFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(options) + ".exe"; if (options.HasFlag(CompilerOptions.Library)) { exeFile = Path.ChangeExtension(exeFile, ".dll"); } var executable = Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile); var decompiled = Tester.DecompileCSharp(executable.PathToAssembly, settings); CodeAssert.FilesAreEqual(csFile, decompiled); }
async Task Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) { var vbFile = Path.Combine(TestCasePath, testName + ".vb"); var csFile = Path.Combine(TestCasePath, testName + ".cs"); var exeFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(options) + ".exe"; if (options.HasFlag(CompilerOptions.Library)) { exeFile = Path.ChangeExtension(exeFile, ".dll"); } var executable = await Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile).ConfigureAwait(false); var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings).ConfigureAwait(false); CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray()); }
void RunCS([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug) { string testFileName = testName + ".cs"; string testOutputFileName = testName + Tester.GetSuffix(options) + ".exe"; CompilerResults outputFile = null, decompiledOutputFile = null; try { outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options, outputFileName: Path.Combine(TestCasePath, testOutputFileName)); string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options)); if (options.HasFlag(CompilerOptions.UseMcs)) { // For second pass, use roslyn instead of mcs. // mcs has some compiler bugs that cause it to not accept ILSpy-generated code, // for example when there's unreachable code due to other compiler bugs in the first mcs run. options &= ~CompilerOptions.UseMcs; options |= CompilerOptions.UseRoslynLatest; // Also, add an .exe.config so that we consistently use the .NET 4.x runtime. File.WriteAllText(outputFile.PathToAssembly + ".config", @"<?xml version=""1.0"" encoding=""utf-8""?> <configuration> <startup> <supportedRuntime version=""v4.0"" sku="".NETFramework,Version=v4.0,Profile=Client"" /> </startup> </configuration>"); } decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options); Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile); Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile)); Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly)); } finally { if (outputFile != null) { outputFile.TempFiles.Delete(); } if (decompiledOutputFile != null) { decompiledOutputFile.TempFiles.Delete(); } } }
public static CompilerResults CompileVB(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) { List <string> sourceFileNames = new List <string> { sourceFileName }; foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)""")) { sourceFileNames.Add(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFileName), match.Groups[1].Value))); } var preprocessorSymbols = GetPreprocessorSymbols(flags).Select(symbol => new KeyValuePair <string, object>(symbol, 1)).ToList(); if (flags.HasFlag(CompilerOptions.UseRoslyn)) { var parseOptions = new VisualBasicParseOptions(preprocessorSymbols: preprocessorSymbols, languageVersion: LanguageVersion.Latest); var syntaxTrees = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f)); var references = defaultReferences.Value; if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { references = references.Concat(visualBasic.Value); } var compilation = VisualBasicCompilation.Create(Path.GetFileNameWithoutExtension(sourceFileName), syntaxTrees, references, new VisualBasicCompilationOptions( flags.HasFlag(CompilerOptions.Library) ? OutputKind.DynamicallyLinkedLibrary : OutputKind.ConsoleApplication, platform: flags.HasFlag(CompilerOptions.Force32Bit) ? Platform.X86 : Platform.AnyCpu, optimizationLevel: flags.HasFlag(CompilerOptions.Optimize) ? OptimizationLevel.Release : OptimizationLevel.Debug, deterministic: true )); CompilerResults results = new CompilerResults(new TempFileCollection()); results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); var emitResult = compilation.Emit(results.PathToAssembly); if (!emitResult.Success) { StringBuilder b = new StringBuilder("Compiler error:"); foreach (var diag in emitResult.Diagnostics) { b.AppendLine(diag.ToString()); } throw new Exception(b.ToString()); } return(results); } else if (flags.HasFlag(CompilerOptions.UseMcs)) { throw new NotSupportedException("Cannot use mcs for VB"); } else { var provider = new VBCodeProvider(new Dictionary <string, string> { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); options.GenerateExecutable = !flags.HasFlag(CompilerOptions.Library); options.CompilerOptions = "/optimize" + (flags.HasFlag(CompilerOptions.Optimize) ? "+" : "-"); options.CompilerOptions += (flags.HasFlag(CompilerOptions.UseDebug) ? " /debug" : ""); options.CompilerOptions += (flags.HasFlag(CompilerOptions.Force32Bit) ? " /platform:anycpu32bitpreferred" : ""); options.CompilerOptions += " /optioninfer+ /optionexplicit+"; if (preprocessorSymbols.Count > 0) { options.CompilerOptions += " /d:" + string.Join(",", preprocessorSymbols.Select(p => $"{p.Key}={p.Value}")); } if (outputFileName != null) { options.OutputAssembly = outputFileName; } options.ReferencedAssemblies.Add("System.dll"); options.ReferencedAssemblies.Add("System.Core.dll"); options.ReferencedAssemblies.Add("System.Xml.dll"); if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { options.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll"); } CompilerResults results = provider.CompileAssemblyFromFile(options, sourceFileNames.ToArray()); if (results.Errors.Cast <CompilerError>().Any(e => !e.IsWarning)) { StringBuilder b = new StringBuilder("Compiler error:"); foreach (var error in results.Errors) { b.AppendLine(error.ToString()); } throw new Exception(b.ToString()); } return(results); } }
public static CompilerResults CompileCSharp(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) { List <string> sourceFileNames = new List <string> { sourceFileName }; foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)""")) { sourceFileNames.Add(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFileName), match.Groups[1].Value))); } if (flags.HasFlag(CompilerOptions.ReferenceCore)) { sourceFileNames.Add(targetFrameworkAttributeSnippetFile.Value); } var preprocessorSymbols = GetPreprocessorSymbols(flags); if ((flags & CompilerOptions.UseMcsMask) == 0) { CompilerResults results = new CompilerResults(new TempFileCollection()); results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); var(roslynVersion, languageVersion) = (flags & CompilerOptions.UseRoslynMask) switch { 0 => ("legacy", "5"), CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "6"), CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest"), CompilerOptions.UseRoslyn3_11_0 => ("3.11.0", "latest"), _ => (RoslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") }; var cscPath = roslynToolset.GetCSharpCompiler(roslynVersion); IEnumerable <string> references; if ((flags & CompilerOptions.UseRoslynMask) != 0) { if (flags.HasFlag(CompilerOptions.ReferenceCore)) { references = coreDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); } else { references = roslynDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); } } else { references = defaultReferences.Value.Select(r => "-r:\"" + r + "\""); } if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { if ((flags & CompilerOptions.UseRoslynMask) != 0) { references = references.Concat(visualBasic.Value.Select(r => "-r:\"" + r + "\"")); } else { references = references.Concat(new[] { "-r:\"Microsoft.VisualBasic.dll\"" }); } } string otherOptions = $"-noconfig " + $"-langversion:{languageVersion} " + $"-unsafe -o{(flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- ")}"; // note: the /shared switch is undocumented. It allows us to use the VBCSCompiler.exe compiler // server to speed up testing if (roslynVersion != "legacy") { otherOptions += "/shared "; } if (flags.HasFlag(CompilerOptions.Library)) { otherOptions += "-t:library "; } else { otherOptions += "-t:exe "; } if (flags.HasFlag(CompilerOptions.GeneratePdb)) { otherOptions += "-debug:full "; } else { otherOptions += "-debug- "; } if (flags.HasFlag(CompilerOptions.Force32Bit)) { otherOptions += "-platform:x86 "; } else { otherOptions += "-platform:anycpu "; } if (preprocessorSymbols.Count > 0) { otherOptions += " \"-d:" + string.Join(";", preprocessorSymbols) + "\" "; } ProcessStartInfo info = new ProcessStartInfo(cscPath); info.Arguments = $"{otherOptions}{string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}"; info.RedirectStandardError = true; info.RedirectStandardOutput = true; info.UseShellExecute = false; Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); Process process = Process.Start(info); var outputTask = process.StandardOutput.ReadToEndAsync(); var errorTask = process.StandardError.ReadToEndAsync(); Task.WaitAll(outputTask, errorTask); process.WaitForExit(); Console.WriteLine("output: " + outputTask.Result); Console.WriteLine("errors: " + errorTask.Result); Assert.AreEqual(0, process.ExitCode, "csc failed"); return(results); } else { CompilerResults results = new CompilerResults(new TempFileCollection()); results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); string testBasePath = RoundtripAssembly.TestDir; if (!Directory.Exists(testBasePath)) { Assert.Ignore($"Compilation with mcs ignored: test directory '{testBasePath}' needs to be checked out separately." + Environment.NewLine + $"git clone https://github.com/icsharpcode/ILSpy-tests \"{testBasePath}\""); } string mcsPath = (flags & CompilerOptions.UseMcsMask) switch { CompilerOptions.UseMcs5_23 => Path.Combine(testBasePath, @"mcs\5.23\bin\mcs.bat"), _ => Path.Combine(testBasePath, @"mcs\2.6.4\bin\gmcs.bat") }; string otherOptions = " -unsafe -o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- "); if (flags.HasFlag(CompilerOptions.Library)) { otherOptions += "-t:library "; } else { otherOptions += "-t:exe "; } if (flags.HasFlag(CompilerOptions.UseDebug)) { otherOptions += "-g "; } if (flags.HasFlag(CompilerOptions.Force32Bit)) { otherOptions += "-platform:x86 "; } else { otherOptions += "-platform:anycpu "; } if (preprocessorSymbols.Count > 0) { otherOptions += " \"-d:" + string.Join(";", preprocessorSymbols) + "\" "; } ProcessStartInfo info = new ProcessStartInfo(mcsPath); info.Arguments = $"{otherOptions}-out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}"; info.RedirectStandardError = true; info.RedirectStandardOutput = true; info.UseShellExecute = false; Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); Process process = Process.Start(info); var outputTask = process.StandardOutput.ReadToEndAsync(); var errorTask = process.StandardError.ReadToEndAsync(); Task.WaitAll(outputTask, errorTask); process.WaitForExit(); Console.WriteLine("output: " + outputTask.Result); Console.WriteLine("errors: " + errorTask.Result); Assert.AreEqual(0, process.ExitCode, "mcs failed"); return(results); } }
public static CompilerResults CompileCSharp(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) { List <string> sourceFileNames = new List <string> { sourceFileName }; foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)""")) { sourceFileNames.Add(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFileName), match.Groups[1].Value))); } var preprocessorSymbols = new List <string>(); if (flags.HasFlag(CompilerOptions.UseDebug)) { preprocessorSymbols.Add("DEBUG"); } if (flags.HasFlag(CompilerOptions.UseRoslyn)) { var parseOptions = new CSharpParseOptions(preprocessorSymbols: preprocessorSymbols.ToArray()); var syntaxTrees = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f)); var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(sourceFileName), syntaxTrees, defaultReferences.Value, new CSharpCompilationOptions( flags.HasFlag(CompilerOptions.Library) ? OutputKind.DynamicallyLinkedLibrary : OutputKind.ConsoleApplication, platform: flags.HasFlag(CompilerOptions.Force32Bit) ? Platform.X86 : Platform.AnyCpu, optimizationLevel: flags.HasFlag(CompilerOptions.Optimize) ? OptimizationLevel.Release : OptimizationLevel.Debug, allowUnsafe: true, deterministic: true )); CompilerResults results = new CompilerResults(new TempFileCollection()); results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); var emitResult = compilation.Emit(results.PathToAssembly); if (!emitResult.Success) { StringBuilder b = new StringBuilder("Compiler error:"); foreach (var diag in emitResult.Diagnostics) { b.AppendLine(diag.ToString()); } throw new Exception(b.ToString()); } return(results); } else { preprocessorSymbols.Add("LEGACY_CSC"); var provider = new CSharpCodeProvider(new Dictionary <string, string> { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); options.GenerateExecutable = !flags.HasFlag(CompilerOptions.Library); options.CompilerOptions = "/unsafe /o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+" : "-"); options.CompilerOptions += (flags.HasFlag(CompilerOptions.UseDebug) ? " /debug" : ""); options.CompilerOptions += (flags.HasFlag(CompilerOptions.Force32Bit) ? " /platform:anycpu32bitpreferred" : ""); if (preprocessorSymbols.Count > 0) { options.CompilerOptions += " /d:" + string.Join(";", preprocessorSymbols); } if (outputFileName != null) { options.OutputAssembly = outputFileName; } options.ReferencedAssemblies.Add("System.Core.dll"); CompilerResults results = provider.CompileAssemblyFromFile(options, sourceFileNames.ToArray()); if (results.Errors.Cast <CompilerError>().Any(e => !e.IsWarning)) { StringBuilder b = new StringBuilder("Compiler error:"); foreach (var error in results.Errors) { b.AppendLine(error.ToString()); } throw new Exception(b.ToString()); } return(results); } }
public static CompilerResults CompileVB(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) { List <string> sourceFileNames = new List <string> { sourceFileName }; foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)""")) { sourceFileNames.Add(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFileName), match.Groups[1].Value))); } var preprocessorSymbols = GetPreprocessorSymbols(flags).Select(symbol => new KeyValuePair <string, object>(symbol, 1)).ToList(); if (!flags.HasFlag(CompilerOptions.UseMcs)) { CompilerResults results = new CompilerResults(new TempFileCollection()); results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); var(roslynVersion, languageVersion) = (flags & CompilerOptions.UseRoslynMask) switch { 0 => ("legacy", "11"), CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "14"), CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest"), _ => (RoslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") }; var vbcPath = roslynToolset.GetVBCompiler(roslynVersion); IEnumerable <string> references; if ((flags & CompilerOptions.UseRoslynMask) != 0) { if (flags.HasFlag(CompilerOptions.ReferenceCore)) { references = coreDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); } else { references = roslynDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); } } else { references = defaultReferences.Value.Select(r => "-r:\"" + r + "\""); } if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { if ((flags & CompilerOptions.UseRoslynMask) != 0) { references = references.Concat(visualBasic.Value.Select(r => "-r:\"" + r + "\"")); } else { references = references.Concat(new[] { "-r:\"Microsoft.VisualBasic.dll\"" }); } } string otherOptions = $"-noconfig " + "-optioninfer+ -optionexplicit+ " + $"-langversion:{languageVersion} " + $"/optimize{(flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- ")}"; // note: the /shared switch is undocumented. It allows us to use the VBCSCompiler.exe compiler // server to speed up testing if (roslynVersion != "legacy") { otherOptions += "/shared "; } if (flags.HasFlag(CompilerOptions.Library)) { otherOptions += "-t:library "; } else { otherOptions += "-t:exe "; } if (flags.HasFlag(CompilerOptions.GeneratePdb)) { otherOptions += "-debug:full "; } else { otherOptions += "-debug- "; } if (flags.HasFlag(CompilerOptions.Force32Bit)) { otherOptions += "-platform:x86 "; } else { otherOptions += "-platform:anycpu "; } if (preprocessorSymbols.Count > 0) { otherOptions += " \"-d:" + string.Join(",", preprocessorSymbols.Select(kv => kv.Key + "=" + kv.Value)) + "\" "; } ProcessStartInfo info = new ProcessStartInfo(vbcPath); info.Arguments = $"{otherOptions}{string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}"; info.RedirectStandardError = true; info.RedirectStandardOutput = true; info.UseShellExecute = false; Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); Process process = Process.Start(info); var outputTask = process.StandardOutput.ReadToEndAsync(); var errorTask = process.StandardError.ReadToEndAsync(); Task.WaitAll(outputTask, errorTask); process.WaitForExit(); Console.WriteLine("output: " + outputTask.Result); Console.WriteLine("errors: " + errorTask.Result); Assert.AreEqual(0, process.ExitCode, "vbc failed"); return(results); } else { throw new NotSupportedException("Cannot use mcs for VB"); } }
public static CompilerResults CompileCSharp(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) { List <string> sourceFileNames = new List <string> { sourceFileName }; foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)""")) { sourceFileNames.Add(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFileName), match.Groups[1].Value))); } var preprocessorSymbols = GetPreprocessorSymbols(flags); if (flags.HasFlag(CompilerOptions.UseRoslyn)) { var parseOptions = new CSharpParseOptions( preprocessorSymbols: preprocessorSymbols.ToArray(), languageVersion: flags.HasFlag(CompilerOptions.Preview) ? Microsoft.CodeAnalysis.CSharp.LanguageVersion.Preview : Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8 ); var syntaxTrees = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f, encoding: Encoding.UTF8)); if (flags.HasFlag(CompilerOptions.ReferenceCore)) { syntaxTrees = syntaxTrees.Concat(new[] { SyntaxFactory.ParseSyntaxTree(targetFrameworkAttributeSnippet) }); } IEnumerable <MetadataReference> references; if (flags.HasFlag(CompilerOptions.ReferenceCore)) { references = coreDefaultReferences.Value; } else { references = defaultReferences.Value; } if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { references = references.Concat(visualBasic.Value); } var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(sourceFileName), syntaxTrees, references, new CSharpCompilationOptions( flags.HasFlag(CompilerOptions.Library) ? OutputKind.DynamicallyLinkedLibrary : OutputKind.ConsoleApplication, platform: flags.HasFlag(CompilerOptions.Force32Bit) ? Platform.X86 : Platform.AnyCpu, optimizationLevel: flags.HasFlag(CompilerOptions.Optimize) ? OptimizationLevel.Release : OptimizationLevel.Debug, allowUnsafe: true, deterministic: true )); CompilerResults results = new CompilerResults(new TempFileCollection()); results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); string pdbName = null; if (flags.HasFlag(CompilerOptions.GeneratePdb)) { pdbName = Path.ChangeExtension(outputFileName, ".pdb"); } var emitResult = compilation.Emit(results.PathToAssembly, pdbName); if (!emitResult.Success) { StringBuilder b = new StringBuilder("Compiler error:"); foreach (var diag in emitResult.Diagnostics) { b.AppendLine(diag.ToString()); } throw new Exception(b.ToString()); } return(results); } else if (flags.HasFlag(CompilerOptions.UseMcs)) { CompilerResults results = new CompilerResults(new TempFileCollection()); results.PathToAssembly = outputFileName ?? Path.GetTempFileName(); string testBasePath = RoundtripAssembly.TestDir; if (!Directory.Exists(testBasePath)) { Assert.Ignore($"Compilation with mcs ignored: test directory '{testBasePath}' needs to be checked out separately." + Environment.NewLine + $"git clone https://github.com/icsharpcode/ILSpy-tests \"{testBasePath}\""); } string mcsPath = Path.Combine(testBasePath, @"mcs\2.6.4\bin\gmcs.bat"); string otherOptions = " -unsafe -o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- "); if (flags.HasFlag(CompilerOptions.Library)) { otherOptions += "-t:library "; } else { otherOptions += "-t:exe "; } if (flags.HasFlag(CompilerOptions.UseDebug)) { otherOptions += "-g "; } if (flags.HasFlag(CompilerOptions.Force32Bit)) { otherOptions += "-platform:x86 "; } else { otherOptions += "-platform:anycpu "; } if (preprocessorSymbols.Count > 0) { otherOptions += " \"-d:" + string.Join(";", preprocessorSymbols) + "\" "; } ProcessStartInfo info = new ProcessStartInfo(mcsPath); info.Arguments = $"{otherOptions}-out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}"; info.RedirectStandardError = true; info.RedirectStandardOutput = true; info.UseShellExecute = false; Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); Process process = Process.Start(info); var outputTask = process.StandardOutput.ReadToEndAsync(); var errorTask = process.StandardError.ReadToEndAsync(); Task.WaitAll(outputTask, errorTask); process.WaitForExit(); Console.WriteLine("output: " + outputTask.Result); Console.WriteLine("errors: " + errorTask.Result); Assert.AreEqual(0, process.ExitCode, "mcs failed"); return(results); } else { var provider = new CSharpCodeProvider(new Dictionary <string, string> { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); options.GenerateExecutable = !flags.HasFlag(CompilerOptions.Library); options.CompilerOptions = "/unsafe /o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+" : "-"); string debugOption = " /debug"; if (flags.HasFlag(CompilerOptions.GeneratePdb)) { debugOption += ":full"; options.IncludeDebugInformation = true; } options.CompilerOptions += (flags.HasFlag(CompilerOptions.UseDebug) ? debugOption : ""); options.CompilerOptions += (flags.HasFlag(CompilerOptions.Force32Bit) ? " /platform:anycpu32bitpreferred" : ""); if (preprocessorSymbols.Count > 0) { options.CompilerOptions += " /d:" + string.Join(";", preprocessorSymbols); } if (outputFileName != null) { options.OutputAssembly = outputFileName; } options.ReferencedAssemblies.Add("System.dll"); options.ReferencedAssemblies.Add("System.Core.dll"); options.ReferencedAssemblies.Add("System.Xml.dll"); options.ReferencedAssemblies.Add("Microsoft.CSharp.dll"); if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { options.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll"); } CompilerResults results = provider.CompileAssemblyFromFile(options, sourceFileNames.ToArray()); if (results.Errors.Cast <CompilerError>().Any(e => !e.IsWarning)) { StringBuilder b = new StringBuilder("Compiler error:"); foreach (var error in results.Errors) { b.AppendLine(error.ToString()); } throw new Exception(b.ToString()); } return(results); } }