The short answer is that you've got the relationship the wrong way around: csc.exe
depends on Roslyn, not vice versa.
The long answer requires a short history lesson:
Originally in the .NET framework, csc.exe
was a self-contained binary responsible for compiling C# source code to IL. But it was opaque and its command-line interface limited what could be achieved by invoking it.
Microsoft introduced the System.CodeDom
namespace and classes as a way for their own tools to generate code (e.g. the Windows Forms designer in Visual Studio), but pretty much everyone started using it because it was miles better than csc.exe
. However given what it was created for, CodeDOM suffers from numerous limitations and edge cases that make it less than ideal for certain non-compilation tasks - and at the end of the day it simply invokes csc.exe
to produce compiled code.
Ultimately this approach was unable to satisfy Microsoft's own need for better static analysis of code in their flagship IDE. To achieve this requirement a new API was required, and Microsoft realised that if they designed it to be accessible to ordinary developers, they could kill two birds with one stone. Thus the Roslyn project was born: a complete set of independent and complete APIs that could be used by anyone, thereby fulfilling the needs of both developers and Visual Studio.
The ultimate result is that all the logic that had lived in csc.exe
migrated into Roslyn's APIs, and the way those APIs are invoked determines what C# language version will be used. Passing -langversion
to csc.exe
or /p:TargetFrameworkVersion
to msbuild.exe
ultimately ends up setting the Roslyn language version for compilation, but there is nothing stopping you from creating your own Roslyn compilation instance to achieve the same.
Reference: https://stackoverflow.com/a/7854697/70345