6

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.

  • 1
    Each .net version that is installed should have its own `csc.exe`. – Bradley Uffner Sep 24 '19 at 14:43
  • 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. – Aaron Beaudoin Sep 24 '19 at 15:00
  • 1
    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. – Lex Li Sep 24 '19 at 15:35
  • 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? – Aaron Beaudoin Sep 24 '19 at 16:16

3 Answers3

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://stackoverflow.com/a/7854697/70345

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
  • 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. – Aaron Beaudoin Sep 24 '19 at 16:29
0

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

msbuild <project-or-solution> /p:TargetFrameworkVersion=v2.0
leppie
  • 115,091
  • 17
  • 196
  • 297
  • 2
    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. – Aaron Beaudoin Sep 24 '19 at 15:04
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.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • 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. – Aaron Beaudoin Sep 24 '19 at 16:07
  • @Damien_The_Unbeliever 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) – JoshVarty Sep 24 '19 at 17:58
  • 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. – Aaron Beaudoin Sep 25 '19 at 20:09