Friday, 23 October 2015

Compiling C# 6.0 code using Roslyn Microsoft.CodeAnalysis v1.0.0 Programmatically

Since the release of recent release of Roslyn aka Microsoft.CodeAnlysis all the article and blogs on internet which were written using Alpha\Beta version of Roslyn are now out dated.
Recently I wanted to write a program using latest stable version (v1.0.0) of Roslyn to compile the CSharp6 versioned code against .Net 4.6 framework. In old beta version there was no option for specifying Target framework and compiler RunTime or maybe I missed it somehow. So I was wondering how to achieve in latest release. I tried searching internet, stackoverflow but finally I end reading and comparing old methods to new and renamed methods and finally created a working sample.

Roslyn Version – Microsoft.CodeAnalysis version="1.0.0"

Install it from Nuget:

> Install-Package Microsoft.CodeAnalysis -Version 1.0.0

Sharing my initial observations of this encounter:

1. Roslyn have become more extensible.

2. Less dependency on the platform version on Roslyn based utilities.

3. The problem was with one package “Microsoft.Workspaces.Desktop” which failed by build because this library requires 4.5.2 or latest .Net version 4.6. So I had to install 4.6 to make it working.

4. Now you can specify almost everything required for customized compilation.

Here’s my complete program. This is a console application that compile a csharp file to Dll. The latest functions in Roslyn have options to supply more information e.g. which platform you want to use for Compilation and what compilation or language version you want to use.

public class Program
{
private static readonly IEnumerable<string> DefaultNamespaces =
new[]
{
"System",
"System.IO",
"System.Net",
"System.Linq",
"System.Text",
"System.Text.RegularExpressions",
"System.Collections.Generic"
};

private static string runtimePath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\{0}.dll";

private static readonly IEnumerable<MetadataReference> DefaultReferences =
new[]
{
MetadataReference.CreateFromFile(string.Format(runtimePath, "mscorlib")),
MetadataReference.CreateFromFile(string.Format(runtimePath, "System")),
MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Core"))
};

private static readonly CSharpCompilationOptions DefaultCompilationOptions =
new CSharpCompilationOptions(OutputKind.WindowsRuntimeApplication)
.WithOverflowChecks(true)
.WithOptimizationLevel(OptimizationLevel.Release)
.WithUsings(DefaultNamespaces);

public static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null)
{
var stringText = SourceText.From(text, Encoding.UTF8);
return SyntaxFactory.ParseSyntaxTree(stringText, options, filename);
}

public static void Main(string[] args)
{
var fileToCompile = @"C:\Users\....\Documents\Visual Studio 2013\Projects\ConsoleForEverything\SignalR_Everything\Program.cs";
var source = File.ReadAllText(fileToCompile);
var parsedSyntaxTree = Parse(source, "", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6));

var compilation
= CSharpCompilation.Create("Test.dll", new SyntaxTree[] { parsedSyntaxTree }, DefaultReferences, DefaultCompilationOptions);
try
{
var result = compilation.Emit(@"c:\temp\Test.dll");

Console.WriteLine(result.Success ? "Sucess!!" : "Failed");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.Read();
}
}
Although this program could have been much better with all refactoring and organizing but this will give you a kick start.

The new Code Analyzer and CSharp syntax rewriters are more interesting things and are on my list to explore.

No comments:

Post a Comment