FSharp.Compiler.Service uses latest TargetFramework when compiling scripts rather than environment.
- Dominant language
- F#
- Stars
- 4.3k
- Forks
- 876
- Avg merge
- 4d 22h
- Merged PRs (30d)
- 144
Description
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
Contributor guide
Assessment
This issue has not been assessed yet.