So I have a PR, weirdly enough it's a pretty big one: https://github.com/dotnet/fsharp/pull/7463
It builds a nuget package with only a netstandard2.0 build of FSharp.Core.dll. That means no desktop specific FSharp.Core after F# 5.0. Well, a developer can always use the FSharp.Core 4.7 nuget package for that scenario.
Apps built using it, will only be able to run on .Net4.6.1 or up. However, I believe the recommended desktop framework to use for netstandard2.0 compatability is .NET 4.7.2
There is a slight issue with command line compilation.
When building an .fsproj file msbuild does a great job of collecting all of the required and possibly required references.
However, if a developer manually types:
fsc program.fs -r:SomePathTo\FSharp.Core.dll
the compiler says … hmmm you better specify your framework assemblies too
specifically:
error FS1222: When mscorlib.dll or FSharp.Core.dll is explicitly referenced the --noframework option must also be passed
That requires the developer to specify the framework assemblies required. The compiler helps out with mscorlib.dll and if you omit it, it finds one anyway.
Unfortunately, with this change you need to tell the build to look for: netstandard.dll, System.Numerics.dll and System.dll
I am conflicted about whether to do this automagically … because the developer was required to specify … --noframework . The reason I have any conflict, is the compiler helpfully will find mscorlib.dll even though the developer said --noframework.
Specifying these paths is only required if a developer paths to FSharp.Core.dll, if the developer omits that reference then we automagically find everything needed. We do this a lot in our testing, but in the real world, I hope it rarely happens at all. Indeed Ideally a developer will always use a .fsproj to specify the build.
Anyway comments … suggestions …
So this is about removing the requirement to put ‘—noframework’ when an FSharp.Core was given? Maybe we can change the issue title to reflect that or is this a broader discussion?
Generally, when I have run into the FS1222 Error in the past it was because of programming against FCS or running fsc programmatically. In those scenarios most of the times it was good to be forced to think about the runtime requirements and choose the correct references in compilation time.
On the other hand given the inconsistencies you mention I would be fine with dropping that error.
What about reducing it to a warning and emitting it for mscorlib as well?
@matthid, actually, no. But perhaps that is an approach.
In the past you could
fsc --noframework somepathTo\FSharp.Core.dll -r:somePathTo\mscorlib.dll
and it would successfully compile and run.
When you do this with the netstandard2.0 only version of FShafrp.Core it is going to give an error:
````
program.fs(5,3): error FS0074: The type referenced through 'System.Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard'.
program.fs(7,5): error FS0074: The type referenced through 'System.IO.TextWriter' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard'.
program.fs(8,5): error FS0074: The type referenced through 'System.Int32' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard'.
````
The issue is, that the netstandard20 only fsharp.core is technically a breaking change, I it would have built before but will no longer build.
It turns out that we even helpfully would find an mscorlib.dll, if you forgot to specify it. But we never aggressively found other framework dlls.
My inclination is to say … never mind, developers should fix their scripts or use an earlier FSharp.Core or even better, don't specify the path to fsharp.core.
fsc Program.fs works perfectly
program.fs(5,3): error FS0074: The type referenced through 'System.Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard'.
Is this even the correct error message? when noframework is given the compiler should stop assuming anything about the framework assemblies. Why does it assume the user wants netstandard?
noframework is the only way to remove magic assumptions the compiler makes so I have to specify everything manually. Isn’t this why the flag exists?
Yes if people specify noframework and use framework assemblies (for example net451) and now update to netstandard only fsharp core it will break, but isn’t this expected? If this scenario worked in the past it was more by accident than anything?
Regarding not specifying noframework, yes we could suggest that in the error message?
Can you clarify again what the suggestion is? Is it to make the noframework basically a no-op argument?
@matthid I am notreally suggesting making any changes to --noframework. I am pointing out that a build script that would previously have successfully built will now fail to build.
Yes if people specify noframework and use framework assemblies (for example net451) and now update to netstandard only fsharp core it will break, but isn’t this expected? If this scenario worked in the past it was more by accident than anything?
In this case the developer didn't update to netstandard, we updated FSharp.Core to be compatible with both the desktop and Coreclr by using netstandard2.0 references. And now their build scripts are not working, the choice was ours rather than theirs. Albeit, their choice not to use .fsproj is the real culprit
Is this even the correct error message? when noframework is given the compiler should stop assuming anything about the framework assemblies. Why does it assume the user wants netstandard?
noframework is the only way to remove magic assumptions the compiler makes so I have to specify everything manually. Isn’t this why the flag exists?It is the correct error message; it happens because FSharp.Core.dll when built for netstandard2.0 has a reference to a type in netstandard.dll, and the build script doesn't specify where that is and so the compiler it can't find the assembly to load to get the type; the compiler isn't assuming, it's complaining.
as you suggest --noframework means the developer is responsible for providing the paths to each of the required framework assemblies. However, due to long existing bit of "helpfulness" (aka bug), the compiler will always fallback to the ambient mscorlib ensuring that simple apps that only use types in mscorlib will still compile.
I don't know, and can't even rationalize why specifying the path to FSharp.Core requires the developer to specify the paths to framework assemblies by demanding the --noframework switch. Although perhaps it was done in the Silverlight 2 and 3 timeframes when mscorlib for Silverlight and the desktop had different API's, I believe they were rationalized only in the net 4.5 timeframe, if that is the case then this is no problem and the compiler is being over-strict.
Interestingly the csc compiler has a -nosdkpath switch to eliminate sdk automagic search. However, given that the sdk directory is different when targeting netstandard, netcoreapp and desktop frameworks, and that information is not supplied to the compiler, it's still probably not a great going-forward design for us.
Perhaps we can:
i. No longer require --noframework, if the path to fsharp.core is specified, which would allow automagic to happen.
ii. if --noframework is specified and no framework assembly reference is specified then ignore it.
iii. Or per your suggestion, deprecate and/ignore --noframework completely
As far as I can tell, the options are:
I guess my preferred solution having catalogued them is 3. Remove the need for --noframework when specifying fsharp.core, and if it is specified with no actual framework assemblies specified then "do automagic" Although I am still partial to "do nothing"
My head actually hurts now.
Just some notes (generally, I agree with your points):
Or per your suggestion, deprecate and/ignore
--noframeworkcompletely
This is not my suggestion :).
In fact, I'd suggest quite the contrary: Leave --noframework to the user and fail if anything is missing. If --noframework is missing we can just make it work with any "magic" we feel necessary. My suggestion would be to not do any mix as it will confuse users even more.
So I'm OK with having i., skeptical regarding ii. and iii. . I'm not sure if this meets backwards compat requirements, but we should try to list the concrete scenarios where users are broken before considering ii. or iii. and see if other solutions exist.
So …
1.. lets try : No longer require --noframework, if the path to fsharp.core is specified.
Then when a developer see's the error, the fix is either to remove --noframework and let magic happen. Or to fully specify the extra framework assembly requirements such as --netstandard.
Closing old discussion
Most helpful comment
So …
1.. lets try : No longer require --noframework, if the path to fsharp.core is specified.
Then when a developer see's the error, the fix is either to remove --noframework and let magic happen. Or to fully specify the extra framework assembly requirements such as --netstandard.