How do I tell the Roslyn C# compiler to use a specific version of .NET?
Asked Answered
L

3

7

I've discovered that the csc.exe binary that comes with Roslyn can take a -langversion:<string> command line argument in order to set the version of C# I would like to compile. But how do I choose which version of .NET I would like the compiler to use?

The compilation process works just fine for my simple test program that uses some .NET SQL Server features, so I know that the compiler is somehow using a version of .NET on my computer. My C:\Windows\Microsoft.NET\Framework directory has multiple versions of .NET in it, and I'm assuming the compiler is using one of those. I would like to explicitly set which version of .NET the compiler uses when compiling my program.

Note: If you can elaborate a little on how the compiler chooses a version in the first place that would be much appreciated as well.

Liquorice answered 24/9, 2019 at 14:40 Comment(4)
Each .net version that is installed should have its own csc.exe.Institute
I am aware of this. However, I am not using any csc.exe binary which is bundled with a version of .NET. Roslyn can be downloaded by itself with nuget.exe and run from wherever you want.Liquorice
There is no such thing. The target framework version is a MSBuild project property, which leads to different sets of referenced assemblies being used during compilation.Petry
If that is true, then how is the csc.exe binary in my Roslyn directory able to build my program without being invoked through msbuild? It has to somehow be automatically finding a .NET framework version to use since I installed Roslyn on its own separately from .NET and because I have multiples versions of .NET available on my system. Logically then, shouldn't I be able to control this behavior directly?Liquorice
C
2

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://mcmap.net/q/50276/-microsoft-roslyn-vs-codedom

Crocodile answered 24/9, 2019 at 16:10 Comment(1)
So basically are you saying that when I specify a C# version via the -langversion parameter that Roslyn does something behind the scenes to match that C# version with a version of the .NET framework and that when msbuild is used with /p:TargetFrameworkVersion then Roslyn matches the supplied .NET framework version with a version of C# language all before actually compiling? If so then it seems that creating a Roslyn compilation instance would be the only way to manually pair two specific versions of C# and .NET.Liquorice
P
1

I just use this from the command line (ie 2.0 below)

msbuild <project-or-solution> /p:TargetFrameworkVersion=v2.0
Pitzer answered 24/9, 2019 at 14:47 Comment(1)
Roslyn does not have msbuild included, and from what I understand, msbuild just uses csc.exe underneath anyways. Since the csc.exe binary included with Roslyn is clearly able to compile using a version of .NET on its own, there must be a way to tell csc.exe directly which .NET version I want to use.Liquorice
W
0

Assuming a fairly recent build of csc,

csc -langversion:?

Will tell you which version of the language that build of csc uses by default1.

From a comment on another answer:

there must be a way to tell csc.exe directly which .NET version I want to use

There is, and you've already identified it in the first line of your question - pass a -langversion parameter.


If you want to know which version you should use, just use the default. If it's not complaining about syntax errors, it's likely good enough. If you're using particular language features, you might try the "What's new in C# x.x" documents to work out which version it was introduced in.


1If it gives you an error, it doesn't support it. Run csc /? instead and the documentation for -langversion should list supported versions. The default is the last version number listed.

Warn answered 24/9, 2019 at 15:36 Comment(3)
I am under the impression that the actual C# language and the .NET framework are considered somewhat independent, allowing you to mix and match versions however you want as long as you do not use any C# language features that depend on at least a certain version of the .NET framework. Are you saying that the -langversion argument automatically implies some .NET version along with the explicitly supplied C# language version? Because if so then that would seem to indicate that C# versions are tightly coupled with .NET versions, which doesn't seem right.Liquorice
@Warn I believe language version (eg. C# 7 vs C# 4) is mostly independent from .NET version (eg. .NET 4.5 vs .NET 3.5). If I understand correctly, there probably isn't a way to specify .NET version from csc. You'd have to end up linking in the right System DLLs manually. (or using msbuild)Logroll
But this again evokes the same confusion of how the Roslyn csc.exe binary manages to compile on its own with .NET somehow in the first place. It must somehow know where to find the correct DLLs by itself. Where is this configured and how do I control it? I did find that the included csc.rsp file has a list of common framework DLL filenames that should be automatically included unless -noconfig is specifed, but how is it choosing which paths to look in for these filenames? I suppose that if I can control this path then I can control which .NET version I include.Liquorice

© 2022 - 2024 — McMap. All rights reserved.