dotnet / fsharp

The F# compiler, F# core library, F# language service, and F# tooling integration for Visual Studio
https://dotnet.microsoft.com/languages/fsharp
MIT License
3.93k stars 786 forks source link

F#5 compiler + net20 target framework = build error #10442

Open SteveGilham opened 4 years ago

SteveGilham commented 4 years ago

As it says -- this was observed with a project that worked happily under SDK 3.1.403 after moving to 5.0.100

Not sure if an oversight or something deliberate, but it means there's something that can be done in current C# that can't be done with current F# any more.

Repro steps

We can still target net20 in a C# program with the net5.0 SDK and it "just works"

dotnet new console -lang C#

edit to set

    <TargetFramework>net20</TargetFramework>

Add reference assemblies

dotnet add package Microsoft.NETFramework.ReferenceAssemblies.net20

and run

>dotnet run
Hello World!

Doing the same for F#

dotnet new console -lang F#

edit to set

    <TargetFramework>net20</TargetFramework>

dotnet adding either of net necessary packages Microsoft.NETFramework.ReferenceAssemblies.net20 or FSharp.Core v4.1.18 (about the latest with a net20 offering) fail with messages like

info : Package 'FSharp.Core' is compatible with all the specified frameworks in project '$(ProjectPath)'.
error: Error while performing Update for package 'FSharp.Core'. Cannot edit items in imported files -

Manually editing to add the packages (equivalent to taking an pre-existing functioning-at-3.1 project and using the new tooling)

  <ItemGroup>
    <PackageReference Update="FSharp.Core" Version="4.1.18" />
    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net20" Version="1.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
</ItemGroup>

and doing dotnet run gives

FSC : error FS0078: Unable to find the file 'System.Numerics.dll' in any of↔ ~\.nuget\packages\microsoft.netframework.referenceassemblies.net20\1.0.0\build\.NETFramework\v2.0↔ $(ProjectDir)↔ C:\Program Files\dotnet\sdk\5.0.100\FSharp\ [$(ProjectDir)\$(ProjectName).fsproj]

The build failed. Fix the build errors and run again.

Expected behavior

Anything we can do with C# we can do in F#

Actual behavior

As above

Known workarounds

Use an older F# compiler

dotnet add package FSharp.Compiler.Tools -v 10.2.3

and build with MSBuild (plain dotnet run gives an interesting error, to wit The file extension of 'C:\Program Files\dotnet\sdk\5.0.100\FSharp\fsc.exe' is not recognized. )

msbuild $(ProjectPath)

whereupon the program can be run without building

>dotnet run --no-build
Hello world from F#

Related information

cartermp commented 4 years ago

cc @KevinRansom

KevinRansom commented 4 years ago

@SteveGilham, FSharp.Core 5.0 is netstandard 2.0 only, and so will not work with net20. If you want to run on old desktop runtimes, reference an earlier version of FSharp.Core. netstandard2.0 is expected to work on .NetFramework 4.7.2 and up.

I hope this helps.

SteveGilham commented 4 years ago

1) As noted above, referencing an earlier FSharp.Core e.g. by dotnet add package FsharpCore -v 4.1.8 fails

2) As noted above, even after editing the project file manually to add FSharp.Core v4.1.8 and the net20 reference assemblies, the F#5 compiler balks because System.Numerics was not a separate assembly pre net40; the appropriate code was contained within the FSharp.Core.dll assembly

KevinRansom commented 4 years ago

Well ... it wasn't expected to work ... it wasn't supported, we never tested it.

You should consider updating to target a non-deprecated target framework. Ideally 4.7.2 since that is really the one with full netstandard 2.0 support.

C# has always been lucky in that their runtime libraries have always been distributed with NET framework. FSharp.Core has never been distributed that way, that has caused us to sometimes have to increase the minimum target framework for FSharp.Core when new useful APIs appear. T.B.H. I have been fighting off people wanting to update FSharp.Core to netstandard 2.1 which would eliminate desktop framework targets at all.

We realized when we moved up to netstandard2.0 we would leave some desktop TFMs behind. It is true though that we thought we had abandoned net20 a lot earlier.

Sorry I can't be more helpful,

Kevin

SteveGilham commented 4 years ago

The profusion of quite interesting error messages did suggest neglect/not-tested rather than a hard and explicit end-of-support (e.g. by emitting something like NETSDK1138, only as a build error, not a warning).

It's no problem if it's formally unsupported at the current level, while a valid workround exists that I can use to maintain legacy support.

KevinRansom commented 4 years ago

I might be able to do something to stop it requiring specific dlls loading. Which should enable the 4.1.18 nuget package to work again. Although it still won't be a supported or tested scenario. I strongly suggest updating to net4.8.

SteveGilham commented 4 years ago

That would be super!

As background -- the one particular assembly affected is the coverage recorder for AltCover, which is, yes, a codebase that's now over 10 years old, and for which net20 offers sufficient APIs for it to function.

Using that API set also meets the primary requirement that -- as the instrumented code all gets linked to a copy of this assembly -- it makes no demands of the platform the consumer is using while testing; and the secondary, box-checking, requirement that the project does everything that OpenCover can.

cartermp commented 3 years ago

Tracking as a bug as the key thing - explicitly referencing an older FSharp.Core that is compatible with this framework - should work.

fsb4000 commented 3 years ago

Thank you @SteveGilham for the workaround. It works for .NET 6.0 also.

SteveGilham commented 3 years ago

Interesting difference in behaviour with .net sdk 6.0.100 -- using dotnet new console -lang f# -o n2 and editing n2.fsproj to be like

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net20</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Program.fs" />
    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net20" Version="1.0.2">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Update="FSharp.Core" Version="4.1.18" />
  </ItemGroup>

</Project>

i.e with suitable FSharp.Core and framework references for the net20 target, issuing dotnet run gives

FSC : error FS0078: Unable to find the file 'System.Numerics.dll' in any of↔ ...\.nuget\packages\microsoft.netframework.referenceassemblies.net20\1.0.2\build\.NETFramework\v2.0↔ [project directory]↔ C:\Program Files\dotnet\sdk\6.0.100\FSharp\
FSC : error FS0229: Error opening binary file '...\.nuget\packages\fsharp.core\4.1.18\lib\net20\FSharp.Core.dll': Stream does not support writing.
FSC : error FS3160: Problem reading assembly '...\.nuget\packages\fsharp.core\4.1.18\lib\net20\FSharp.Core.dll': The exception has been reported. This internal exception should now be caught at an error recovery point on the stack. Original message: Error opening binary file '...\.nuget\packages\fsharp.core\4.1.18\lib\net20\FSharp.Core.dll': Stream does not support writing.)
error FS0073 : internal error : BuildFrameworkTcImports: no successful import of ...\.nuget\packages\fsharp.core\4.1.18\lib\net20\FSharp.Core.dll

Copying an existing System.Numerics.dll into the project folder silences the first error, but not the cascade about trying to open the nuget cache file for write.