question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

FSharp.Compiler.Service uses latest TargetFramework when compiling scripts rather than environment.

See original GitHub issue

Not sure if this is a bug or a feature request.

I am using FSharp.Compiler.Service to compile user created F# scripts. Up until today, the code was working as expected however after I updated to .NET 7 the script compilation succeeds but attempting to load/reflect into the script fails with:

Could not load file or assembly 'System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

After some investigation what seems to be happening is when FSharpChecker.Compile is given an fsx file, it implicitly creates an fsproj file with the TargetFramework=net7.0 (based on the latest SDK installed?). The rest of my solution is targeting net6.0 so it can’t find the correct version of System.Runtime.

Repro steps

A concise repro is not simple. The key parameters are described below.

    let checker = FSharpChecker.Create()

    // https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/compiler-options
    let compilerArgs (scriptPath:string) (dllPath) = 
        [|
            "-a"; scriptPath
            $"-o:%s{dllPath}"
            "--targetprofile:netcore"
            "--target:library"
            "--debug:full"
            $"--compilertool:%s{Assembly.GetExecutingAssembly().DirectoryName}"
        |]

    let tryCompile scriptPath dllPath =
        async {
            let compilerArgs = compilerArgs scriptPath loadCtx.DllFullName
            let! errors, retCode = checker.Compile(compilerArgs)
            // omitted a bunch of code that handles copying of reference assemblies
            let assembly = // ... code loads the dll into its own AssemblyLoadContext
            let types = assembly.GetTypes() // calling this method throws the exception

As an attempted workaround I placed a global.json into the runtime directory:

{
    "sdk": {
      "version": "6.0.0",
      "rollForward": "latestMinor"
    }
}

Then with some scripts I get a compiler error. To cause this behaviour the script must have some dependencies to trigger the creation of a .fsproj on disk. #r "nuget: FSharp.Data, 5.0.2" seems to be sufficient for this. Simple scripts produce the same System.Runtime exception from above.

C:\Path\To\main.fsx (2,1)-(2,31) parse error C:\Program Files\dotnet\sdk\6.0.306\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.TargetFrameworkInference.targets(144,5): error NETSDK1045: The current .NET SDK does not support targeting .NET 7.0.  Either target .NET 6.0 or lower, or use a version of the .NET SDK that supports .NET 7.0. [C:\Path\To\bin\Projects\31412--0815da43-918d-4e85-baef-19d36d3e76bf\Project.fsproj]

Expected behavior

My initially expected behavior is that selecting a particular version of FSharp.Compiler.Service (I tried with 41.0.6 and 41.0.7) corresponding to FSharp.Core 6.0.6 and 6.0.7 would set the TargetFramework=net6.0 and FSharp.Compiler.Service 42.7.1 would set the TargetFramework=net7.0.

I would have also expected the compiler to consider the presence of global.json and set the TargetFramework based on that.

I searched extensively to see if there was some way to instruct FSharpChecker on what TargetFramework to use e.g. with compiler args. Possibly there could be an overload to Compile or new method added to FSharpChecker which provides some direct control over the implicitly generated fsproj file.

Known workarounds

None tested. Expect that uninstalling the latest .NET so that only .NET 6 SDKs were present on the system would succeed. My update to .NET 7 happened as part of automatic updates to Visual Studio.

Related information

Provide any related information (optional):

  • Operating system: Windows 10
  • dotnet --list-sdks 5.0.104 [C:\Program Files\dotnet\sdk] 6.0.111 [C:\Program Files\dotnet\sdk] 6.0.202 [C:\Program Files\dotnet\sdk] 6.0.203 [C:\Program Files\dotnet\sdk] 6.0.306 [C:\Program Files\dotnet\sdk] 7.0.100 [C:\Program Files\dotnet\sdk]
  • Editing Tools: Visual Studio 17.4.0

Issue Analytics

  • State:open
  • Created 10 months ago
  • Reactions:1
  • Comments:11 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
KevinRansomcommented, Nov 10, 2022

Yes, this is definitely an issue.

The behavior generating default references does not do what is expected. I did a bunch of cleanup around that code a month or two ago, I may have broken something. Although it may also have been broken a lot longer than that.

Here is a complete straightforward repro: FCS_14289_Repro.zip

It produces this output:

scriptPath: C:\Users\codec\source\repos\FCS_14289_Repro\FCS_14289_Repro\script\repro_14289.fsx
dllPath:    C:\Users\codec\source\repos\FCS_14289_Repro\FCS_14289_Repro\bin\Debug\net6.0\repro_14289.dll
References:    System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
References:    FSharp.Core, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
References:    netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51

System.Runtime should be 6.0.0.0 because of the presence of the global.json file with this specification:

{
  "sdk": {
    "version": "6.0.402"
  }
}
0reactions
sritharanscommented, Apr 5, 2023

@KevinRansom There seems to be a workaround to this issue, using a solution posted here: https://github.com/dotnet/fsharp/issues/14250

Read more comments on GitHub >

github_iconTop Results From Across the Web

Notes and Guidance on FSharp.Core
Notes and Guidance on FSharp.Core. This technical guide discusses the FSharp.Core library. Reference documentation for FSharp.Core can be found here: ...
Read more >
FSharp.Compiler.Service
Service package is a component derived from the F# compiler source code that exposes additional functionality for implementing F# language bindings, additional ...
Read more >
F# Interactive (dotnet) Reference
F# Interactive attempts to compile the code and, if successful, it executes the code and prints the signature of the types and values...
Read more >
fsautocomplete 0.56.2
A community-developed Language Server Protocol implementation for F#.
Read more >
The Good and the Bad of .NET Framework Programming
NET that happened to be a more modular framework than its predecessor. ... NET uses two compilers, Roslyn, to compile C# or VB...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found