Page MenuHomePhabricator

C# modules fail to find compiler on newly configured machine
Open, Needs TriagePublicBUG REPORT

Description

Steps to replicate the issue (include links if applicable):

  • Set up a machine in a way that only Framework 4.0 needs to be installed
  • Load AWB with a settings file that contains an active module

What happens?:

  • Error dialog: could not find csc.exe

What should have happened instead?:

  • Module compiled without error, and executes.

Software version:
Windows 10 or 11 without Framework 3.5 installed. Note AWB itself requires 4.x.

It turns out that the CSharpCodeProvider uses the provided compiler version to look up the location of csc.exe inside the registry key HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\MSBuild\ToolsVersions\3.5 (in a 64-bit machine anyway; in the case of an x86 machine the unvirtualized version is read), corresponding to the 3.5 compiler version specified by AWB. On new systems, that key does not exist.

The user can hack a new key 3.5 into the registry alongside the existing 4.0 key, and add a string value MSBuildToolsPath:C:\Windows\Microsoft.NET\Framework64\v4.0.30319\

The requested AWB fix is to change the three "3.5" references to "4.0" in the source, or specify an empty providerOptions dictionary to the CSharpCodeProvider constructors and let the framework code find the compiler. That works for me but may have other failure modes.

Event Timeline

That would indeed be an easy fix...

I wonder if we can do it without hardcoding, using the version AWB is currently running with? That way we don't forget to update it again in the future...

https://learn.microsoft.com/en-us/dotnet/api/microsoft.csharp.csharpcodeprovider.-ctor?view=net-8.0

In .NET Framework apps, you can obtain the value for providerOptions from the <providerOption> element in the configuration file. You can identify the version of the CSharpCodeProvider you want to use by specifying the <providerOption> element, supplying "CompilerVersion" as the option name, and supplying the version number (for example, "v3.5") as the option value. You must precede the version number with a lower case "v". The following configuration file example demonstrates how to specify that version 3.5 of the C# code provider should be used.

Certainly if we require (and/or are running on) 4.5, we have to specify 4.0

A quick Google (as I'm on my way out the door) doesn't yield any obvious answers, but what you say about not specifying the version...

I'd be curious in seeing how that behaves... Does it pick the current/applicable version to what is being run? The newest? The oldest etc installed?

I'm certainly happy (and can do it later today when I'm on a different machine) to at least fix the hardcoding to a newer version for now...

I can have a play with the non hardcoded version locally too, on a machine with various versions installed and see if it's obvious what it choses to do

The current logic (according to the Framework reference source RedistVersionInfo.cs) is:

  • Use the option CompilerDirectoryPath if present
  • Use the value from Executor.GetRuntimeInstallDirectory() if there is no CompilerVersion option, or it is set to 4.0
  • If the CompilerVersion is 2.0 or 3.5, look in the registry for the directory, which requires Framework 3.5 installation, or a registry hack
  • Any other CompilerVersion is an error.

The GetRunTimeInstallDirectoryImpl is internal and not listed anywhere I can find, but I guess is usually C:\Windows\Microsoft.NET\Framework\v4.0.30319.