-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Enabling AOT with package lock files is adding a dependency to Microsoft.NET.ILLink.Tasks
#38200
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
This is likely a bug which is tracked in the SDK repository: dotnet/sdk#38200 Closes SIANXSVC-1202
This is likely a bug which is tracked in the SDK repository: dotnet/sdk#38200 Closes SIANXSVC-1202
This is likely a bug which is tracked in the SDK repository: dotnet/sdk#38200 Closes SIANXSVC-1202
This is likely a bug which is tracked in the SDK repository: dotnet/sdk#38200 Closes SIANXSVC-1202
We're seeing the same issue, which has broken our build pipelines a couple of times in the last few months (We use I think we've got a workaround for this by using a {
"sdk": {
"version": "8.0.202",
"rollForward": "disable"
}
} But we expect this to cause some friction with local development, since Visual Studio will often uninstall older SDK versions when updated. We'll also need to manually update the SDK version rather than relying on the rollforward behaviour. |
Note: We're seeing this in projects with |
@dotnet/illink-contrib a new issue has been filed in the ILLink area, please triage |
@dotnet/illink-contrib Would it make sense to change Microsoft.NET.ILLink.Tasks so that it is consumed as a PackageDownload instead of a PackageReference? We think this would fix the issue where lock files for AOT projects get invalidated for every servicing update. |
The package needs to participate in the restore package imports since it contains build logic. I don't think PackageDownload supports that, does it? |
@TomGathercole I also thought this could be a workaround for us but we ran into the issue with "dotnet restore --locked-mode" not respecting global.json: |
@vedion You're right disabling rollforward doesn't work. This broke for us again today, and the only solution appears to be to update to the latest SDK as soon as it becomes available (Which seems to happen monthly). I do wonder why more people aren't hitting this - it seems to be something that'll fundamentally happen when using a combination of blazor and |
This seems to be related: |
I have the same problem where locked restore fails when the lock file was generated using a different SDK version. It only works when the machine where the packages are restored is using an identical SDK version. I suspect not many people use As a workaround, I added a direct package reference for |
@sliekens it is exactly the workaround that I am using. When multi-targeting, I override the package per target framework. |
The Runtime/Linker team strongly recommend not pinning the package and letting the SDK resolve it to ensure compatibility between the runtime in use (which is determined by the SDK version used) and the linker/tools used (which as has been discussed here is also determined by the SDK version in use). @dsplaisted this scenario is one case where your proposal for source-build would also solve the problem here. Since it seems like implicit packages are not suited to lock files, the SDK could make use of your proposed mechanism for all such implicit packages, removing the need (or even ability) for the user to pin the different versions and letting the SDK control the entire set of used versions. |
@baronfel That is easier said then done. Currently it is the only option. Otherwise I have to choose between AoT or reproducible builds. |
Our position is that you should pin the SDK itself in this case - use global.json to enforce uniformity across your team. If you're not doing that then you are subject to nonreproducible builds in hundreds of other ways, because the compilers themselves (to say nothing of the build logic) can and do change with every SDK. Essentially I think you're missing the forest for the trees - since the lockfile gives you an easy way to see thing that have changed, you're missing all of the other things that you can't see that also change. |
@baronfel I get the point here, but pinning the exact SDK version is problematic as I am using Azure DevOps and SDKs get added and removed constantly. And I am again I a situation where I would have to choose between two things that I want to have both. It's a lot of little things (including this issue) which makes things more complicated and frustrating as they should be (from my POV). |
If you use a global.json, you can control the SDKs in use for a given pipeline using the UseDotNet task in AzDo - there's an analogue for this in GitHub Actions as well (actions/setup-dotnet). This is a supported mechanism that we encourage anyone interested in consistency to use! |
This is why I like Dev Containers, to containerize all these devtools and make it easy to pin the SDK version. Even my CI pipeline runs in a container, using the same Docker image that I use in VSCode. It's really too bad that VS2022 doesn't support dev containers. |
Build reproducibility is already tied to the .NET SDK version. For example if you create a simple "Hello World" style app and then build it on the 8.0.100 and 8.0.105 .NET SDK you will get a different binary. That is because the PDB embeds the version of the .NET Runtime, compiler and a few other tools, that were used to create the binary. It's unclear how deep of reproducible you're looking for here but if it's byte for byte then switching .NET SDK versions is already breaking that. |
I don't think this is true. In Azure Pipelines, this breaks for us even with a global.json. (See #38200 (comment) above from @vedion). The restore seems to break simply from having the newer SDKs available. |
Many thanks for pointing that out. Always good to learn new things. In most cases my requirements for a reproducible build is at dependency/package level. That's why I use the package lock and ended up here :-). |
I considered this some time ago but found that the task is messing with the pathes and would make any pre-installed runtimes "invisible", which I need for testing a multi-targeted library project. But thanks for the hint. I'll give it a try. Maybe it's an option for application projects. |
@smkanadl you should be able to use the task multiple times in the same pipeline to set up any arrangement of SDKs you need - I've certainly done similar with GitHub actions for my own projects. |
@baronfel I know - but contradicts the bonus of having pre-installed runtimes/SDKs and adds quite to the execution time. But fair point 👍 |
EDIT: Solved it myself. Stupid me forgot to delete the @baronfel I gave your suggestions another try and for some cases they work pretty well. Thanks for reminding me! It get's a bit more troublesome for multi-target cases. I use SDK 8.0.205 for build a trimmable library for net8.0 and net7.0 together with a locked restore. On my dev machine (win) the lock files contain references to In my CI pipeline I use the latest Unfortunately the restore failes as it tries to restore How does the SDK determines the package version for older TFMs? The main difference between local dev and CI seems to be the OS (win/linux) and the fact that I have various other versions of the DSK installed. |
The version is determined by |
@sbomer it was actually me being stupid. I had a rollForward to the next minor release in my global.json, so it was 8.0.300 used to generate the locks and 8.0.205 to restore them. Once fixed it worked flawlessly. Thank you very much for your explanation! |
We have one project that is enabling I have 8.0.303 installed, so with "Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.7, )",
"resolved": "8.0.7",
"contentHash": "iI52ptEKby2ymQ6B7h4TWbFmm85T4VvLgc/HvS45Yr3lgi4IIFbQtjON3bQbX/Vc94jXNSLvrDOp5Kh7SJyFYQ=="
}, If I set "Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.6, )",
"resolved": "8.0.6",
"contentHash": "E+lDylsTeP4ZiDmnEkiJ5wobnGaIJzFhOgZppznJCb69UZgbh6G3cfv1pnLDLLBx6JAgl0kAlnINDeT3uCuczQ=="
}, The |
I like the idea of excluding SDK dependencies from the packages lock file. In essence, global.json already fulfills the role of locking the sdk version and its dependencies like the ILLink stuff. Currently, you have to pin the SDK version to an exact patch number if you want to use lock files. If SDK dependencies were removed from the lock file, the behavior would remain exactly the same for those who pinned their SDK version to a patch, while enabling others to pin to a SDK channel, or not even pin the SDK at all. |
Until dotnet/sdk#38200 is resolved
* Remove dotnet restore locked mode Until dotnet/sdk#38200 is resolved * Update lockfile * Wildcard sdk version * Harden runners
Describe the bug
When enabling the
IsAotCompatible
property together withRestorePackagesWithLockFile
, dotnet addsMicrosoft.NET.ILLink.Tasks
as a direct dependency to the lock file. As an effect, even patch updates of the .NET SDK (e.g. from 8.0.100 to 8.0.101) ends up in breaking package builds.Therefore, even a patch update ends up in being a breaking change, although it should not have an effect on the NuGet package.
To Reproduce
dotnet new console
.IsAotCompatible
andRestorePackagesWithLockFile
in the.csproj
.packages.lock.json
looks like this (on my system with .NET 8.0.100):An example gist with the project files shows the minimum code required to reproduce it.
Further technical details
Output of
dotnet --info
The text was updated successfully, but these errors were encountered: