Open jabbera opened 4 years ago
Hi! Is there any chance of this getting prioritized? Just trying to plan.
is this ever going to happen?
I've given up.
I can reproduce this issue on .NET Core Console App
that multi-targets net472
and a .NET core tfm. I cannot reproduce this issue on a .NET Core Class Library
project with multiple target frameworks.
@nkolev92 helped me to find that .NET SDK
sets runtime identifier to win7-86
here. It looks like following comment in the .targets
file confirms this behavior.
When building a .NETFramework exe on Windows and not given a RID, we'll pick either win7-x64 or win7-x86
Transferring to dotnet/SDK
team for feedback.
This issue is plaguing us also.
Hey all,
The root problem here is that the SDK projects have different defaults depending on the environment they are being built in.
The RID scenario is one example, and the other example is the one displayed in the diff.
In particular, in order to build .NET Framework projects on linux, the SDK automatically adds a targeting pack reference which can be disabled through AutomaticallyUseReferenceAssemblyPackages
. Refer to the discussion in https://github.com/NuGet/Home/issues/10456 for more detail.
Given that you are trying to build on linux, I think you need to explicitly reference the targeting pack to unblock yourself.
@nkolev92 I don't understand what you mean. I am explicitly referencing the targeting pack: https://github.com/jabbera/nuget-locked-mode-bug/blob/e9977b0f1438fed2377afb4554abae13f899988f/bugdemo.csproj#L10
I also don't think anything that was mentioned would actually help my scenario. I am building on Linux but then running all of my tests on multiple platforms. As part of that step I am running a dotnet restore on windows where the lock file was generated on linux. I don't see how any of these suggestions will help me.
@jabbera
Did you notice @kartheekp-ms's comment about the RIDS?
And in my comment above I mention: https://github.com/NuGet/Home/issues/9195#issuecomment-777065637
The root problem here is that the SDK projects have different defaults depending on the environment they are being built in.
If you are going to build on different OSs, consider including the RuntimeIdentifier in your project explicitly instead of relying on environment defaults that the SDK sets.
Hopefully that should make the dotnet restore --locked-mode
call work.
using <DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
solved some of our issues when restoring on different platforms.
While not a solution, I'm now using the workaround below. It disables lock files on all platforms except Windows (the primary development + deployment target). This doesn't block me from using other OS's, littering my workspace with changes to packages.lock.json
:
<!-- Enable nuget lock files. -->
<RestorePackagesWithLockFile Condition="'$(OS)' == 'Windows_NT'">true</RestorePackagesWithLockFile>
<!-- On CI builds restore the exact versions as locked. -->
<RestoreLockedMode Condition="'$(OS)' == 'Windows_NT' And '$(ContinuousIntegrationBuild)' == 'true'">true</RestoreLockedMode>
<!-- Force nuget to ignore existing lock files. -->
<NuGetLockFilePath Condition="'$(OS)' != 'Windows_NT'">no.lock.file</NuGetLockFilePath>
If you want, you could also have a lock file per OS. This prevents the lock files from being changed all the time between OS's, but also that when updating your dependencies it involves updating the lock files from multiple OS's:
<!-- Enable nuget lock files. -->
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<!-- On CI builds restore the exact versions as locked. -->
<RestoreLockedMode Condition="'$(ContinuousIntegrationBuild)' == 'true'">true</RestoreLockedMode>
<!-- Lock file per OS. -->
<NuGetLockFilePath>packages.$(OS).lock.json</NuGetLockFilePath>
Is there any update on this or perhaps an "official" workaround?
Our primary development enviroment is windows (one dev is on macos), but we do all CI and deployments on Linux, with our primary distributable a Linux docker image. Despite the docker build/artifact we do primary development outside of docker, direct in vs/vscode. Ideally the lock file would be generated/updated there and then copied into our docker builds.
I've added DisableImplicitNuGetFallbackFolder=true
and I've tried specifying rid(s) in the project file. For good measure I also tried making use of the DotNet.ReproducibleBuilds.Isolated
package.
Prior to this, I had no rids specified in the project file, but my docker builds do a restore with -r linux-x64
. I tried specifying multiple rids in the project file for windows/Linux and the generated lock files looked "good". But then when I try to restore in the docker image, specifying the single rid, I get an error saying that the target rid (linux-x64
) doesn't match the ones in the lock file (linux-x64;win-x64
)
I'd like to avoid having one lock file per OS. And I'd like to do the generation/updates of the locks on developer machines (of any flavor) via dotnet/msbuild as if docker wasn't in the picture. The work arounds by @Bouke don't really satisfy either case. If developers only used windows then perhaps his first suggestion could work.
Is there any guidance for this scenario?
I created an issue in dotnet/sdk to see if they're willing to remove the RID that's added when restoring/building on Windows, or alternatively help us understand if manually specifying the RID in the project file is unlikely to cause other issues, or any other recommendations they have.
I don't see it mentioned elsewhere, so specifying the RID in the project file seems to "work for me", but MSBuild being what it is, I can't promise there isn't some edge case or scenario where it doesn't work:
<PropertyGroup>
<RuntimeIdentifiers>win7-x86</RuntimeIdentifiers>
</PropertyGroup>
It doesn't matter if you're building on Linux, specifying this in your project makes the RIDs consistent regardless of what platform you're restoring on, so locked mode should work.
Once I get feedback from the SDK team, I'll see about updating docs. For this reason, I'm going to mark this as blocked on external. I don't see what else NuGet can do. I even spent a little time trying to re-imagine lock files implemented in a different way, but I think that NuGet needs the SDK to provide us with consistent inputs. Even if we changed the lock file format, we can't solve this problem for all scenarios, only this "easy" one where there are no RID-specific packages.
@zivkan Is that assuming you'd always do a dotnet restore
?
eg. It wouldn't work if you were trying to build on a Linux box and leveraging something like the Cache task's cacheHitVar
to skip restoring
I don't have experience with the Cache task.
Are you saying that it caches failures, and therefore will fail the build without running restore? If so, yes that's right. However, if it does not cache failures, and keeps re-running restore until the first successful restore, then there should not be any problem.
If it caches failures, the only workaround I can think of is to either change the rid (use win7-x64
instead of win7-x86
, or visa-versa, or use win10-x86
), as you'll need to update the lock file in the same commit as changing the csproj in that case. Alternatively, you can apply the cache task's workaround to "clear" the cache: https://docs.microsoft.com/en-us/azure/devops/pipelines/release/caching?view=azure-devops#q-can-i-clear-a-cache
Actually, having tried that code sample on the linked page I am suspicious that it might be incorrect. Not running dotnet restore
means that project.assets.json
isn't created and then the build phase failed with an error.
I think it is unclear what exactly do if one has <TargetFramework>net7.0</TargetFramework>
defined and would like to publish a cross-platform library and restore dependencies in a cross-platform manner too.
Is a workaround needed? If yes, what should it be? For instance, would
<PropertyGroup Condition="$(TargetFramework.Contains('-windows')) and $(PlatformTarget) == 'x64'">
<Platforms>x64</Platforms>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-windows')) and $(PlatformTarget) == 'x86'">
<Platforms>x86</Platforms>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>
work for libraries that restore dependencies based on developers updating lock files on any OS , are built on CI as in this thread and then distributed through Nuget (and also on WASM)?
This probably starts to be a bit of an issue for libraries that would need to be mindful on package supply-chains (e.g. https://github.com/lumoin/Verifiable) and that would need to consider package locking, Nuget package sources and like that (also it would improve performance).
I'll link https://github.com/dotnet/sdk/issues/1906 and https://github.com/dotnet/sdk/issues/9518 and their linked issues as they give further context on the issue at large in build system. And why it's a bit tough to figure out what works or not.
In addition to the problem described above we depend on an ~700MB OS specific 3rd party vendor NuGet and want to avoid the cost for restoring the Windows NuGet when targeting Linux (on CI).
As a workaround we use a lock file per RID and -p:MyRuntimeIdentifier=...
as described here https://github.com/dotnet/sdk/issues/14281#issuecomment-876510589 with defaults for RID based on the OS platform.
<PropertyGroup>
<MyRuntimeIdentifier Condition="$([MSBuild]::IsOSPlatform('Windows'))">win-x64</MyRuntimeIdentifier>
<MyRuntimeIdentifier Condition="$([MSBuild]::IsOSPlatform('Linux'))">linux-x64</MyRuntimeIdentifier>
<RuntimeIdentifier>$(MyRuntimeIdentifier)</RuntimeIdentifier>
<NuGetLockFilePath>packages.lock.$(RuntimeIdentifier).json</NuGetLockFilePath>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode>true</RestoreLockedMode>
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
</PropertyGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'win-x64'">
<PackageReference Include="Some.Windows.Nuget" Version="..." />
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64'" >
<PackageReference Include="Some.Linux.Nuget" Version="..." />
</ItemGroup>
Create lock files:
dotnet restore -p:MyRuntimeIdentifier=linux-x64 --force-evaluate
dotnet restore -p:MyRuntimeIdentifier=win-x64 --force-evaluate
and commit packages.lock.linux-x64.json
and packages.lock.win-x64.json
files.
Then dotnet restore
, dotnet build
etc just work regardless if on Linux or Windows. Or use a specific RID:
dotnet restore -p:MyRuntimeIdentifier=linux-x64
dotnet build --no-restore -p:MyRuntimeIdentifier=linux-x64
dotnet publish ./web/web.csproj --no-build --runtime linux-x64
Details about Problem
When running a dotnet restore --locked-mode from a linux environment where dotnet restore --force-evaluate was run on windows it fails. This makes things very difficult to test cross platform. (Build on a linux agent then run tests on windows). Note: it happens either way (lockfile generate on linux causes windows to fail)
NuGet product used: dotnet.exe
NuGet version (x.x.x.xxx):
dotnet.exe --version (if appropriate):
OS version (i.e. win10 v1607 (14393.321)): Windows 10 Enterprise: 10.0.18363 and Ubuntu 18..04 (WSL in my case, but repro's on build agents as well)
Worked before? If so, with which NuGet version: Unknown
Detailed repro steps so we can see the same problem
Other suggested things
Output of the diff: