FAKE
FAKE copied to clipboard
Could not find a suitable .NET 6 runtime version matching SDK version: 7.0.100
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
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.
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 😅.
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 [email protected](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 https://github.com/MortalFlesh/console-style/pull/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?
@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.
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 :)
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?
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.
@yazeedobaid sorry, I don't quite get your explanation for 2 reasons:
-
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]
-
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
@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.
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.
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).
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
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.
@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.
this is a horrible option I have hundreds of repos to convert as a result of this change.
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?
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.
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:
- .NET 6 is the current LTS release, and
- 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
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.
i agree with @akhansari Imo, the fake-cli should not be published stable of a version that completely breaks things for everyone.
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
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)
On our side, we've started to remove the runner and switch to the build project.
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
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 https://github.com/cake-build/cake/pull/3990
Also, DotNet.build doesn't seem to work with Microsoft.Build.Framework >=17.4.0 Should be pinned to 17.3.2
edit: https://github.com/fsprojects/FAKE/issues/2722
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).
If anyone is interested in a quick conversion to an .fsx build:
- 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
-
Convert
#r "packet: ..."
to#r "nuget: .."
includes. -
To run use
dotnet fsi build.fsx {args}
instead offake {args}
.
@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)
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.