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

Could not find a suitable .NET 6 runtime version matching SDK version: 7.0.100 #2719

Open
nojaf opened this issue Nov 15, 2022 · 32 comments
Open

Comments

@nojaf
Copy link
Contributor

nojaf commented Nov 15, 2022

Description

I cannot my FAKE using dotnet 7 sdk.

Repro steps

global.json:

{
  "sdk": {
    "version": "7.0.100"
  }
}

install fake-cli 6.0.0-alpha003.
Create empty fsx file.
Run dotnet fake run build.fsx

Consider adding your dependencies via `#r` dependencies, for example add '#r "paket: nuget FSharp.Core //"'.
See https://fake.build/guide/fake-modules.html for details.
If you know what you are doing you can silence this warning by setting the environment variable 'FAKE_ALLOW_NO_DEPENDENCIES' to 'true'
Updating group Main in C:\Users\nojaf\Projects\fake-dotnet7-repro\.fake\build.fsx\paket.dependencies
Resolving dependency graph...
Updated packages:
  Group: Main
    - FSharp.Core: 7.0.0 (added)
Starting full restore process.
Starting task 'DotNet:version': running dotnet --version
7.0.100
Finished (Success) 'DotNet:version' in 00:00:00.1310713
Performance:
 - Cli parsing: 91 milliseconds
 - Packages: 639 milliseconds
   - Resolver: 498 milliseconds (1 runs)
      - Runtime: 28 milliseconds
      - Blocked (retrieving package details): 50 milliseconds (1 times)
      - Blocked (retrieving package versions): 419 milliseconds (1 times)
   - Disk IO: 14 milliseconds
   - Average Request Time: 144 milliseconds
   - Number of Requests: 2
   - Creating Runtime Graph: 1 millisecond
   - Retrieve Assembly List: 2 seconds
 - Script analyzing: 11 milliseconds
 - Runtime: 2 seconds
There was a problem while setting up the environment:
-> Could not find a suitable .NET 6 runtime version matching SDK version: 7.0.100

Expected behavior

It should not fail.

Actual behavior

I find it weird to see a complaint about finding no dotnet 6 runtime.
The check above did find the correct 7.0.100 version

Known workarounds

/

Related information

  • Operating system: Win 11
  • .NET 7
  • Version of FAKE (4.X, 5.X) 6.0.0-alpha003
@yazeedobaid
Copy link
Collaborator

The FAKE runner is locked to .NET 6 runtime assemblies. In FAKE v6. the support for NETSTANDRD 2.0 has been dropped in the runner and it only searches for a .NET 6 SDK references assemblies. If it cannot find any, then the runner will fail with this message.

Supporting multiple reference assemblies causes problems before when we supported NETSTANDARD2.0 and NET 6, and we had to do some workarounds to overcome them - and some we could not, hence we dropped support for NETSTANDARD.

Locking runner to .NET 6 and making it a requirement to use FAKE runner, and providing alternative options to run FAKE; use FSI directly or a dedicated build project (please see Different ways to run FAKE) was the option we went on with, especially since the approach to using a dedicated build project is being adopted recently.

If we can support .NET 7 reference assemblies in runner in a way that will not cause side effects, I'm all ok with that. But just I don't wanna go down that rabbit hole again.

@nojaf
Copy link
Contributor Author

nojaf commented Nov 16, 2022

Hello @yazeedobaid, thanks for explaining the problem space.
I'm currently trying to upgrade an open-source project that happens to use FAKE.
So, I would probably go for the easiest option and convert the script to a project. (If the maintainers approve of course)

The best solution would be to use the reference assemblies of the currently used SDK (assuming it is 6 or higher). But that smells like a rabbit hole for sure 😅.

mthierba added a commit to pbi-tools/pbi-tools that referenced this issue Nov 22, 2022
- TOM 19.52, MSAL 4.48, PBI API 4.11, CsvHelper 30
- Pinned to .Net 6 to work around current Fake incompatibilities with .Net 7 (fsprojects/FAKE#2719, fsprojects/FAKE#2722)
@MortalFlesh
Copy link

Hello,
I'm also trying to use net 7 in my project and I constantly get an error:

Unhandled exception. Fake.Core.BuildFailedException: Target 'AssemblyInfo' failed.
 ---> System.AggregateException: One or more errors occurred. (Could not load file or assembly 'Fake.Core.ReleaseNotes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
)
 ---> System.IO.FileNotFoundException: Could not load file or assembly 'Fake.Core.ReleaseNotes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

File name: 'Fake.Core.ReleaseNotes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null'
   at Build.initTargets@72-4.Invoke(TargetParameter _arg5)
   at Fake.Core.TargetModule.runSimpleInternal(TargetContext context, Target target) in D:\a\FAKE\FAKE\src\app\Fake.Core.Target\Target.fs:line 371
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
   at Fake.Core.TargetModule.raiseIfError(OptionalTargetContext context) in D:\a\FAKE\FAKE\src\app\Fake.Core.Target\Target.fs:line 1319
   at Fake.Core.TargetModule.runOrDefaultWithArguments(String defaultTarget) in D:\a\FAKE\FAKE\src\app\Fake.Core.Target\Target.fs:line 1542
   at Build.main(String[] args)

Before this I used build.fsx but as @yazeedobaid mentioned, there are problems - so I'm trying to use build as a project (inspired by https://github.com/TheAngryByrd/MiniScaffold example).

Foo target works as expected (so does the Clean target).

But when there is a Fake package in use in the target (such as AssemblyInfo or ReleaseNotes.. in AssemblyInfo target), it fails.

I've tried multiple ways of declaring dependencies in paket.dependencies (in group, not in group, ..) but the result is always the same.

All the code is in this PR MortalFlesh/console-style#19 (here is the error https://github.com/MortalFlesh/console-style/actions/runs/3583647906/jobs/6029331205)

Locally it behaves the same.

Am I doing something wrong?

@yazeedobaid
Copy link
Collaborator

@MortalFlesh I cloned the repository you provided on feature/use-net-7 branch and the project build successfully for me and the tests target ran also successfully, I didn't encounter the missing dependency issue but some tests were failing for another reason.

Could you please remove the storage: none statements from paket.dependencies file and re-restore dependencies again? And after that check packages folder, it should contain a directory called build for Build group in your paket.dependencies which has all the FAKE modules you referenced.

@MortalFlesh
Copy link

Well.. I still can't understand, how it worked for you @yazeedobaid :)

I've found a problem and fixed it. Problem was in the Clean target, which removes all bin and obj directories - and it also removed the build/bin and build/obj dir, so the they were missing when next target ran.

So now I can use the build project and I confirm it works on net 7.
Thanks :)

@otto-gebb
Copy link
Contributor

I encountered this issue after upgrading FAKE from 5.23.1 to 6.0.0:

There was a problem while setting up the environment:
-> Could not find a suitable .NET 6 runtime version matching SDK version: 7.0.200

The message confuses me, because I have all the runtimes and SDKs:

❯ dotnet --info                       
.NET SDK:
 Version:   7.0.200
 Commit:    534117727b

Runtime Environment:
 OS Name:     arcolinux
 OS Version:  
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/7.0.200/

Host:
  Version:      7.0.3
  Architecture: x64
  Commit:       0a2bda10e8

.NET SDKs installed:
  3.1.426 [/usr/share/dotnet/sdk]
  6.0.114 [/usr/share/dotnet/sdk]
  7.0.200 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.32 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.14 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.2 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.32 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.14 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.3 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  DOTNET_ROOT       [/usr/share/dotnet]

global.json file:
  Not found

I am using the build.fsx-way of running FAKE in many of my projects and would prefer to keep using it. The only workaround I found is to downgrade FAKE to 5.23.1.

Adding a global.json file fixing the SDK version to v6 like this

{
  "sdk": {
    "version": "6.0.114"
  }
}

also fixes the FAKE script, but it breaks my project, I want to use SDK v7.

Are there any other workarounds?

@yazeedobaid
Copy link
Collaborator

During the upgrade of dependencies of FAKE and Paket.Core in FAKE we had to drop support for NETSTANDARD2.0 in FAKE runner and use .NET 6 reference assemblies. We choose .NET 6 since it is the current LTS release. The SDK resolver in FAKE runner look at the global.json file in the project, and setting it to .NET 7 which is not matching what is pinned will result in that error.

The other workaround is to convert the build script to a dedicated build project as explained here.

@otto-gebb
Copy link
Contributor

@yazeedobaid sorry, I don't quite get your explanation for 2 reasons:

  1. You say

    "...we had to use .NET 6 reference assemblies"

    but I do have both SDK v6 and runtimme v6 installed, as indicated by dotnet --info. See these parts:

    .NET SDKs installed:
      6.0.114 [/usr/share/dotnet/sdk]
    ...
    .NET runtimes installed:
      Microsoft.AspNetCore.App 6.0.14 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
      Microsoft.NETCore.App 6.0.14 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
    
  2. You say

    "The SDK resolver in FAKE runner look at the global.json file in the project..."

    but I dont' have a global.json file. See this part in the output of dotnet --info:

    ...
    global.json file:
      Not found
    

@yazeedobaid
Copy link
Collaborator

@otto-gebb so FAKE runner now uses .NET host to get the current version of .NET SDK using dotnet --version as implemented in 2639 PR and 2665 PR. And from that it ensure that resolved version is based on .NET 6, otherwise it will show the message you are having.

In your case, you have .NET 6 and .NET 7 installed on the machine, but .NET host uses the latest SDK version, so it will be .NET 7, hence you get the error message.

However, when you specified a global.json file and set it to 6.0.114 it worked, but as I understand your projects are using .NET 7 already (so it is a downgrade for you).

The resolution algorithm first try to resolve .NET host from environment variables. I can suggest installing .NET host in another directory and install .NET 6 SDK only in that directory and set DOTNET_HOST_PATH environment variable for FAKE runner to pick it up.

I know this is not a convenient way, but allowing runner to use different reference assemblies will be problematic. We tried before to combine .NETSTANDARD 2.0 and .NET 6 and we hit edge cases that resulted in dropping .NETSTANDRD 2.0

Another option I can suggest is to call your scripts directly using FSI instead of FAKE runner. However, if you are using Paket to resolve dependencies you need to tell FSI about Paket, you can do that by passing --compilertool flag to FSI as explained here Passing the folder of the extension as --compilertool flag.

@rcknight
Copy link
Contributor

Just to add a +1 to this issue, we are in the exact same scenario @otto-gebb - building a net7 project, net6 and 7 installed on the build agent.

If I now can't use fake-cli to build a .net7 project this seems a pretty severe limitation of it's usefulness for us.

@otto-gebb
Copy link
Contributor

Tried the compilertool workaround. Unfortunately, it doesn't work for me, I guess because of a bug in Paket (more specifically, in its handling of the groupref instruction).
image

@otto-gebb
Copy link
Contributor

The workaround using a separate SDK v6 installation works for me.
The commands I used:

curl -s -L -O https://dot.net/v1/dotnet-install.sh
chmod +x ./dotnet-install.sh
./dotnet-install.sh --version "6.0.114" --install-dir "/tmp/dotnet6" \
  --architecture "x64" --os "linux" --no-path
export DOTNET_HOST_PATH=/tmp/dotnet6/dotnet ; fake build

@mthierba
Copy link

Just adding my 2 cents here ... I had the same issue earlier with .Net7 support, and ended up dropping fake-cli and converting the fake build script to fsproj (targeting net6.0):
https://github.com/pbi-tools/pbi-tools/tree/main/build

That works well and leaves you all the options, including building .Net 7 projects via Fake.

@otto-gebb
Copy link
Contributor

@mthierba Yes, that seems to be the best option, and exactly the one I was hoping to avoid, because for me it entails converting tens of scripts across the monorepo.

@BlythMeister
Copy link
Contributor

this is a horrible option I have hundreds of repos to convert as a result of this change.

@BlythMeister
Copy link
Contributor

To enhance this, whilst i understand V6 is a new major and breaking changes can occur.
a breaking change whereby you have to not use the latest framework/SDK OR have to change the way your entire build is orchestrated is huge.

Also, a .net6 app (as compiled) should be able to run on .net7 runtime i thought?

@mthierba
Copy link

To enhance this, whilst i understand V6 is a new major and breaking changes can occur.
a breaking change whereby you have to not use the latest framework/SDK OR have to change the way your entire build is orchestrated is huge.

Also, a .net6 app (as compiled) should be able to run on .net7 runtime i thought?

I believe you need a runtime for the same major .Net version to run a respective compiled app (that's a No to your question), but I couldn't find any hard evidence to support that.

@yazeedobaid
Copy link
Collaborator

I know this will not be convenient for all use cases of FAKE runner and it was a trade-off to make. Let me please explain why we have gone with this approach.

First, the FAKE runner was utilizing NETSTANDARD 2.0 reference assemblies when compiling the build script. NETSTANDARD 2.0 reference assemblies were distributed in a NuGet package and FAKE runner downloaded that package in the background if it is not in the host machine. So it did not cause issues until users starts to use APIs that are not in NETSTANDARD 2.0 reference assemblies and are in later versions of .NET.

That trigger the need to upgrade the reference assemblies used in runner, so we tried to use both options, NETSTANDARD 2.0 and .NET 6. When we cannot find .NET 6 reference assemblies in host machine we revert back to NETSTANDARD 2.0. But that didn't last long, we had several issues in updating dependencies and supporting both reference assemblies.

To that end, we decided to drop support for NETSTANDARD 2.0 reference assemblies and use .NET 6 ones. We didn't go with .NET 7 reference assemblies for two reasons:

  1. .NET 6 is the current LTS release, and
  2. Moving to .NET 7 will leave .NET 6 uses without support.

I know the second reason has the same drawback on both sides since supporting either .NET version will leave the other without support, but .NET 6 won because it is the current LTS. And usually, users stay at LTS releases more than upgrading to newer ones (as far as I know).

What also triggers this is the need to upgrade dependencies that the FAKE codebase relies on to catch up with the echo system in general and Paket.Core specifically.

Also, In FAKE v6, we focused on FAKE modules more than runner, we cleaned them up, replaced obsolete APIs with alternatives, and update them since some were lacking behind services they support/interact with. We tried to not touch the runner as possible, but in the reference assembly part, we could not.

Sorry for the historical writing, but I'm trying to explain why we went with this approach and this decision. If anyone have other alternatives/approaches please let's know.

Thanks

@akhansari
Copy link
Contributor

In this case, this would/should be the end of fake-cli.
Because why use a tool that prevents us to move forward to another dotnet.

@BlythMeister
Copy link
Contributor

i agree with @akhansari
Imo, the fake-cli should not be published stable of a version that completely breaks things for everyone.

@matthid
Copy link
Member

matthid commented Feb 22, 2023

Just my two cents from the sideline:

  • When i decided to build the new runner architecture I thought reference assemblies via NuGet was the new normal, but as we can see, the dotnet Team reiterated on that

  • I also prefer LTS versions, but we should maybe acknowledge that the other versions are fully supported

  • Imo, the fake-cli should not be published stable of a version that completely breaks things for everyone

    I'm not sure on that, as you can lock the version and it was always recommend to do that, that was one of the goals to not break people when doing breaking changes or at least make them more aware that they can happen.

  • I see multiple options going forward:

    • Either follow the net versioning from now on and release a fake v7 with support for net7 reference assemblies, but still support v6 with critical issues (very rare anyway)
    • obsolete the runner completely and make people aware to no longer use it
    • bundle the reference assemblies to the runner instead of finding the SDK
    • do nothing, only support LTS versions

But I'll leave it to you to discuss, find other approaches. And up to @yazeedobaid to decide

@BlythMeister
Copy link
Contributor

As it goes, I created a .net 7 dotnet tool as a wrapper around my script.
Very simple, but need to bulk update all repos to use my new tool rather than fake cli (which is the issue)

Wonder.

Could the CLI tool (only) multi target?
Seems odd that other DSL type build things don't have this issue (Cake for example)

@akhansari
Copy link
Contributor

On our side, we've started to remove the runner and switch to the build project.

@matthid
Copy link
Member

matthid commented Feb 22, 2023

I don't know how cake does it, but to do compilation you need reference assemblies afaik, last time I tried to use runtime assemblies weird stuff happened

@matthid
Copy link
Member

matthid commented Feb 22, 2023

After a quick look it seems like they use https://www.nuget.org/packages/Basic.Reference.Assemblies.Net60/
At least that's my interpretation of cake-build/cake#3990

@akhansari
Copy link
Contributor

akhansari commented Feb 22, 2023

Also, DotNet.build doesn't seem to work with Microsoft.Build.Framework >=17.4.0
Should be pinned to 17.3.2

edit: #2722

@yazeedobaid
Copy link
Collaborator

While working on v6 we intended to focus on modules, not the runner. But while doing that, I was experimenting (a few experiments) with calling FSI and adding Paket to FSI as a compiler tool now that it accepts third-party dependency managers. Still facing some issues, but that will off-load a large portion of the current FAKE runner logic to FSI. One drawback I remember is assembly caching which FSI (as far as currently I know) doesn't have it, so each call will recompile the script. On the other hand, FAKE runner cache assembly and use it.

When a new .NET version is released or Paket, and we try to update to them, the runner will need significant changes or debugging of multiple cases. And having a different version of Paket.Core in the runner from the one that has been used to generate a paket.lock will cause problems. This pattern was reported a few times recently. Which triggers the need to make the runner independent of Paket.Core.

These are the issues reported in runner currently that need to be addressed.

I think keeping the runner with the LTS release support and trying to find solutions to this problem and other related problems by utilizing the new features that are being added to FSI is worth investigating (please correct me if I'm wrong).

@ray440
Copy link

ray440 commented Mar 15, 2023

If anyone is interested in a quick conversion to an .fsx build:

  1. The top of your build.fsx file should look something like this:
#load ".fake/build.fsx/intellisense.fsx"

// Boilerplate
System.Environment.GetCommandLineArgs()
|> Array.skip 2 // skip fsi.exe; build.fsx
|> Array.toList
|> Fake.Core.Context.FakeExecutionContext.Create false __SOURCE_FILE__
|> Fake.Core.Context.RuntimeContext.Fake
|> Fake.Core.Context.setExecutionContext

// the rest of your original build.fsx content...
#r "nuget: Fake.DotNet.Cli"
#r "nuget: Fake.IO.FileSystem"
#r "nuget: Fake.Core.Target"

open System
open System.Diagnostics
open Fake.Core
open Fake.IO
open Fake.IO.Globbing.Operators
  1. Convert #r "packet: ..." to #r "nuget: .." includes.

  2. To run use dotnet fsi build.fsx {args} instead of fake {args}.

@yazeedobaid
Copy link
Collaborator

@ray440 that is also a valid approach. We have this approach documented in the getting started guideline. That section is missing setting up FAKE context statements. We can accept a PR to enhance that approach in documentation if you would like to send one. Run FAKE using F# interactive (FSI)

@pchinery
Copy link
Contributor

I'm joining the conversation, as we ran into the same problem after updating MSBuild to 17.5.

@otto-gebb so FAKE runner now uses .NET host to get the current version of .NET SDK using dotnet --version as implemented in 2639 PR and 2665 PR. And from that it ensure that resolved version is based on .NET 6, otherwise it will show the message you are having.

I'm not sure if I understand the description correctly, but it sounds off to me. dotnet --version will show the latest SDK installed, but fake-cli knows, that it's only able to run on dotnet 6 SDK. But even if that's installed, it will not be used. Is that correct/intended?

If that's how it works today: would it be feasible to look for the latest supported dotnet SDK instead? This would at least not auto-break the runner when a new SDK becomes available, even though I can imagine that it can be tricky to resolve the SDKs.

SilkyFowl added a commit to SilkyFowl/Avalonia.FuncUI.LiveView that referenced this issue May 4, 2023
- Changed Fake build system from fsx script to fsproj.
  - see: https://fake.build/guide/getting-started.html#Different-ways-to-run-FAKE
  - this resolved compatibility issues that [Could not find a suitable .NET 6 runtime version matching SDK version: 7](fsprojects/FAKE#2719).
ivar-rummelhoff added a commit to immortalvm/ivm-implementations that referenced this issue May 24, 2023
We have replaced Fake CLI with a project in order to use .NET 7.0. See
fsprojects/FAKE#2719 and
https://fake.build/guide/getting-started.html#Run-FAKE-using-a-dedicated-build-project
. We are not sure if the resulting solution is optimal or "best practice".
@et1975
Copy link

et1975 commented May 25, 2023

The big problem with running FAKE via FSI is that FSI doesn't support authenticated feeds atm:

build.fsx(3,1): error FS3217: /usr/local/share/dotnet/sdk/7.0.100/NuGet.targets(132,5): warning : The plugin credential provider could not acquire credentials. Authentication may require manual action. Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet` [...SNIP.../.packagemanagement/nuget/Projects/27794--13ea9ba4-9704-42f9-a729-f5294200e009/Project.fsproj]

@cataggar
Copy link
Contributor

cataggar commented May 26, 2023

Thank you @ray440! It would be nice if the boilerplate could be simplified, but using dotnet fsi looks like the best solution going forward. It works with .NET 6 & .NET 7. Visual Studio provides full intellisense. Using a private nuget feed works. Here is an adapted minimal example build.fsx:

#!/usr/bin/env -S dotnet fsi
#r "nuget: Fake.Core.Target"

// Boilerplate
System.Environment.GetCommandLineArgs()
|> Array.skip 2 // skip fsi.exe; build.fsx
|> Array.toList
|> Fake.Core.Context.FakeExecutionContext.Create false __SOURCE_FILE__
|> Fake.Core.Context.RuntimeContext.Fake
|> Fake.Core.Context.setExecutionContext

open Fake.Core

Target.create "clean" (fun _ ->
  Trace.log "Cleaning stuff"
)

Target.create "build" (fun _ ->
  Trace.log "Building the app"
)

Target.create "deploy" (fun _ ->
  Trace.log "Deploying app"
)

open Fake.Core.TargetOperators

"clean"
  ==> "build"
  ==> "deploy"

Target.runOrDefaultWithArguments "build"

Example running the default target on Linux:
image

Example running the deploy target on Windows:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests