dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.73k stars 1.07k forks source link

NuGet package not copied on build/publish, not found on run #10770

Open kg opened 4 years ago

kg commented 4 years ago

I have a simple C# project using two nuget packages that builds and runs fine in VS2017 on Windows set to .NET Core 2.1. If I use dotnet build, dotnet publish or dotnet run in all 3 cases one of the packages is missing from the output directory so it fails to be loaded. dotnet restore doesn't fix this, neither does setting <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> in the csproj.

In the csproj you can see the two dependencies here: https://github.com/kg/wasmdis/blob/master/WasmDis.csproj#L36

If you look at the result of a publish, you can see that the native dependencies for Capstone were copied into the output directory but the managed assembly was not. The managed assembly is present in the .deps.json so the dependency is being tracked somehow.

kate@reeir-debian2:~/Projects/WasmDis$ ls -la bin/Debug/netcoreapp2.1/publish
total 768
drwxr-xr-x 5 kate kate   4096 Mar  5 10:02 .
drwxr-xr-x 6 kate kate   4096 Mar  5 10:09 ..
-rwxr--r-- 1 kate kate 693680 Nov  9 00:56 Newtonsoft.Json.dll
drwxr-xr-x 4 kate kate   4096 Mar  5 10:02 runtimes
-rw-r--r-- 1 kate kate    786 Mar  5 09:59 spidermonkey-driver.js
-rw-r--r-- 1 kate kate   2243 Mar  5 10:09 WasmDis.deps.json
-rw-r--r-- 1 kate kate  37888 Mar  5 10:09 WasmDis.dll
-rw-r--r-- 1 kate kate  13196 Mar  5 10:09 WasmDis.pdb
-rw-r--r-- 1 kate kate    146 Mar  5 10:00 WasmDis.runtimeconfig.json
drwxr-xr-x 2 kate kate   4096 Mar  5 10:02 x64
drwxr-xr-x 2 kate kate   4096 Mar  5 10:02 x86
kate@reeir-debian2:~/Projects/WasmDis$ ls -la bin/Debug/netcoreapp2.1/publish/x64
total 3768
drwxr-xr-x 2 kate kate    4096 Mar  5 10:02 .
drwxr-xr-x 5 kate kate    4096 Mar  5 10:02 ..
-rwxr--r-- 1 kate kate 3847680 Jan 11  2019 capstone.dll
kate@reeir-debian2:~/Projects/WasmDis$ dotnet run
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Gee.External.Capstone, Version=2.0.2.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

It's not clear to me how to debug this and it's kind of disappointing that the error feedback/output doesn't explain that it attempted to load the dependency out of my local package cache (or whatever) and failed.

kg commented 4 years ago

I should note that on my windows machine if I open cmd and perform dotnet run in the project directory, it works despite the bin directory not having the dependency in it.

filipnavara commented 4 years ago

Did you specify any runtime indentifier for the dotnet publish? Eg. dotnet publish -r win-x64; it generates a new subdirectory in the publish output folder.

The Gee.External.Capstone package has a bit unusual structure where the actual implementation is provided only for win-x86 and win-x64 runtimes. If the runtime identifier is not specified it may not copy anything to the output folder:

image

filipnavara commented 4 years ago

I tried it locally on your project:

image

image

Seems to do the job.

kg commented 4 years ago

OK, so it sounds like the package is authored to do this. Does it really make sense for dotnet build/dotnet publish to 'succeed' on a platform and generate an executable that cannot ever possibly work? This feels like a dependency resolution failure that just happens to have been intended by the package author, I would have hoped that some part of the tooling would have noticed it was impossible to resolve the dependency and alert me to it.

Thanks for looking into the metadata, I didn't know how to do that.

filipnavara commented 4 years ago

As always, I really recommend NuGet Package Explorer and MSBuild Log viewer as the go-to tools for digging deep into issues like this.

It is really unusual way to package the NuGet. Normally the managed code is shared across RIDs and the native libraries are packaged under different RIDs. Perhaps there's some good reason for this but it's not a common setup.

I suppose some warning would be nice but not sure how easy is it to do that (wrt. self-contained vs framework-dependent deployments). There are certain scenarios where the assemblies are intentionally omitted from the implementation because they are supplied by the underlying platform. The whole dotnet SDK itself is composed of NuGets and this is probably the common scenario for the platform itself.