Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle updates to core libraries #2001

Closed
matthid opened this issue Jun 18, 2018 · 9 comments
Closed

Handle updates to core libraries #2001

matthid opened this issue Jun 18, 2018 · 9 comments

Comments

@matthid
Copy link
Member

matthid commented Jun 18, 2018

Help for users

To fix the problem you can either:

  • Upgrade the fake runner, not your build dependencies. This process depends on how you installed fake. You can check your version with fake --version. Usually you do choco upgrade fake or reinstall via dotnet tool install

    Hint: If no upgrade exists either use the option below or send a pull request for updating the dependencies in FAKE (fork, clone, run paket update and send a PR)

  • Pin the version of FSharp.Core in your build dependencies. Add nuget FSharp.Core <version> with whatever FAKE suggested. You can see the available versions on NuGet.
    For example, if you get

    Warning: Paket resolved a FSharp.Core with version '4.6.0.0', but fake runs with a version of '4.5.0.0'. This is not supported.
    Please either lock the version via 'nuget FSharp.Core ' or upgrade fake.
    Read #2001 for details.
    

    Add nuget FSharp.Core 4.5.0 to your build dependencies

Description

See dotnet/fsharp#5207 (comment)
and SAFE-Stack/SAFE-template#101

The basic problem is interop between the script context and the fake runtime. There is a narrow interface between those two, for technical reasons (and because it is easier) FSharp.Core is part of that narrow interface.
This means we HAVE TO load the same version of FSharp.Core we use in the runtime into the script context.

Repro steps

Execute an F# script depending on a higher FSharp.Core than the runtime bundles.

Currently implemented Solution

Hook into the paket resolution process and warn the user with a link to this issue if the resolved version is higher. Try to run the script anyway because most of the time this will "just work".

Potential Solution 1

Hook into the paket resolution process and make paket resolve the FSharp.Core version of the runtime

  • Advantages: "Just Works"
  • Disadvantages: Hidden Magic and people might wonder why they do not get latest

Potential Solution 2

Fail early when FSharp.Core doesn't match (is higher) and tell users to lock the FSharp.Core version

  • Disadvantages: Could be a bit stressful for the user

Potential Solution 3

(Basically for completeness sake, not really up for discussion)

Carefully narrow the interface to be "without" FSharp.Core

  • Disadvantage: I don't think you can write F# code without FSharp.Core dependency
  • Disadvantage: Potentially a lot of work
  • Disadvantage: Breaking change

Known workarounds

Don't use dependencies which require higher FSharp.Core versions (ie downgrade/lock lower FSharp.Core version until the fake runtime supports them)

@theimowski
Copy link
Member

In my case I didn't mean to get the latest FSharp.Core version, just pulled necessary dependencies for my FAKE script, i.e.:

group Build
    storage: none
    source https://api.nuget.org/v3/index.json

    nuget Fake.Core.Target
    nuget Fake.DotNet.Cli
    nuget Fake.IO.FileSystem
    nuget Fake.Core.Environment
    nuget Fake.Core.Trace
    nuget Fake.IO.Zip
    github CompositionalIT/fshelpers src/FsHelpers/ArmHelper/ArmHelper.fs

How about locking FSharp.Core in all Fake.* nuspecs? I mean one will probably have at least Fake.Core.Target dependency if running a FAKE script.
Then paket resolution would lock FSharp.Core - wouldn't that solve the problem?

theimowski added a commit to theimowski/SAFE-template that referenced this issue Jun 19, 2018
@matthid
Copy link
Member Author

matthid commented Jun 29, 2018

@theimowski This only has the unfortunate side-effect that FSharp.Core is locked when using the fake nugets as libraries (outside fake runtime). Also there is no technical requirement to use any Fake nuget packages at all and it should probably always work.

but a good thought, thanks!

@0x53A
Copy link
Contributor

0x53A commented Jun 30, 2018

+1 for solution 1

@matthid
Copy link
Member Author

matthid commented Jul 1, 2018

@0x53A I took another look into how to implement and solution 1 is surprisingly difficult to implement correctly.
In fact we will probably go into a mix between 1 and 2. We will add several new warnings for various situations, but the default case we encountered here will "just work" because we will change the reference assembly at script compilation time (just as we change/redirect the reference at runtime).

However we sill will tell the user in a hint that it's a good idea to pin FSharp.Core when this happens. I guess this will come back one way or the other but it probably is never really "critical" as you can always pin yourself.
What I mean with "come back" is that there probably will be reports by confused users... But it's more about getting the error messages useful then anything else.

@matthid matthid closed this as completed in c7ccb03 Jul 1, 2018
@matthid matthid mentioned this issue Jul 8, 2018
@rmunn
Copy link
Contributor

rmunn commented Feb 1, 2019

FSharp.Core 4.6 was just released, causing this to trigger again:

Warning: Paket resolved a FSharp.Core with version '4.6.0.0', but fake runs with a version of '4.5.0.0'. This is not supported.
Please either lock the version via 'nuget FSharp.Core ' or upgrade fake.
Read #2001 for details.

Time to bump FSharp.Core in paket.lock to 4.6?

@forki
Copy link
Member

forki commented Mar 12, 2019

image

I found this in one of my projects. Is this pin still needed?

@matthid
Copy link
Member Author

matthid commented Mar 12, 2019

Latest fake will downgrade for you and warn if it did that

@TeaDrivenDev
Copy link
Contributor

I must admit that I completely fail to understand what any of this means. Am I not allowed to use a newer version of FSharp.Core in the entire solution than FAKE uses? Can I not use FAKE when I want to use the latest FSharp.Core? Where would I need to lock the FSharp.Core version? In my paket.dependencies? In the #r "paket: part of my build script? And to what version? The one I want to use or the one FAKE uses?

@matthid
Copy link
Member Author

matthid commented Apr 14, 2019

@TeaDrivenDev

Am I not allowed to use a newer version of FSharp.Core in the entire solution than FAKE uses?

No, you need to differentiate between "build" and "project" dependencies. They should either go into separate dependency groups or the "build" dependencies should be in the build script "inlined". You should always keep them separate for various reasons.

Can I not use FAKE when I want to use the latest FSharp.Core?

FAKE doesn't force you to use any particular FSharp.Core version in your projects if used as suggested.

Where would I need to lock the FSharp.Core version?

The exact problem is that the FAKE-runner ships it's own FSharp.Core and will always overwrite whatever paket resolves for the "build"-dependencies. This can lead to issues if the version resolved by paket is newer then the one FAKE ships with. Usually, the FAKE-runner will detect the situation and tell you to either downgrade/pin the FSharp.Core version or update the FAKE-runner. (Most times this will "just work" anyway, but it is not a supported scenario)

In my paket.dependencies?

Only if you use a build group and reference that in your build script or use // [FAKE GROUP] otherwise you need to do it within the #r paket: string.

And to what version?

This depends on the FAKE-runner version you use, but it needs to be lower or equal to the shipped one.

The one I want to use or the one FAKE uses?

I hope the above clarifies enough.

knocte added a commit to knocte/FSharpLint that referenced this issue Dec 25, 2023
Because we were getting the following build error:
```
Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:20.36
Finished (Failed) 'DotNet:build' in 00:00:20.8917736
Finished (Failed) 'Build' in 00:00:20.8932132

---------------------------------------------------------------------
Build Time Report
---------------------------------------------------------------------
Target     Duration
------     --------
Clean      00:00:00.0005837
Build      00:00:20.8931029   (Could not load file or assembly 'Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. General Exception (0x80131500))
Test       00:00:00           (skipped)
Total:     00:00:20.9348330
Status:    Failure
---------------------------------------------------------------------
Script reported an error:
-> BuildFailedException: Target 'Build' failed.
-> One or more errors occurred. (Could not load file or assembly 'Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. General Exception (0x80131500))
-> FileLoadException: Could not load file or assembly 'Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. General Exception (0x80131500)
-> Could not load 'Microsoft.Build.Framework, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
   This can happen for various reasons:
   - You are trying to load full-framework assemblies which is not supported
     -> You might try to load a legacy-script with the new netcore runner.
       Please take a look at the migration guide: https://fake.build/guide/fake-migrate-to-fake-5.html
   - The nuget cache (or packages folder) might be broken.
     -> Please save your state, open an issue and then
     - delete 'Microsoft.Build.Framework' from the '~/.nuget' cache (and the 'packages' folder)
     - delete 'paket-files/paket.restore.cached' if it exists
     - delete '<script.fsx>.lock' if it exists
     - try running fake again
     - the package should be downloaded again
   - Some package introduced a breaking change in their dependencies and .dll files are missing in the resolution
     -> Try to compare the lockfile with a previous working version
     -> Try to lower transitive dependency versions (for example by adding 'strategy: min' to the paket group)
     see fsprojects/FAKE#1966 where this happend for 'System.Reactive' version 4

   -> If the above doesn't apply or you need help please open an issue!
Hint: To further diagnose the problem you can run fake in verbose mode `fake -v run ...` or set the 'FAKE_DETAILED_ERRORS' environment variable to 'true'
Warning: Paket resolved a FSharp.Core with version '8.0.0.0', but fake runs with a version of '6.0.0.0'. This is not supported.
Hint: Could not find a version in your paket.dependencies file, consider adding 'version 7.1.5' at the top of your dependencies file (/home/runner/work/FSharpLint/FSharpLint/paket.dependencies).
Please either lock the version via 'nuget FSharp.Core <nuget-version>' or upgrade fake.
Read fsprojects/FAKE#2001 for details.
Read fsprojects/FAKE#2193 for details.
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants