Single-file executable can't find dependency DLL in its folder
The intent is to publish a single-file executable which loads its runtime/native dependencies dynamically from the folder it is located in.
I have ensured that those versions of the dependencies are placed in the same folder as the output.
The project file is:
yet at runtime, though
TerraFX.Interop.Windows.dll
is in the same folder (v. attached image)
There is no issue in Debug. The dependencies are placed in the output folder by an earlier-building project which is also win-x86
, has the same PackageReferences, down to the version (minus the ExcludeAssets bit).
Is there any obvious reason why this would occur that I am missing?
8 Replies
COREHOST_TRACE=1
gist attached https://gist.github.com/fkelava/7072ccfebd8c9481bb6a60a6e6a6ce1c
Contextually, this is a standalone application shipping alongside a plugin framework. Hence certain shared deps are taken untrimmed and shared/loaded dynamically.attached
runtimeconfig
and deps
from single-file package(but when program is executed were you able to check that the correct dll with the correct version is unpacked from the published file?)
the point is that the dependency is not packed in the single-file- a correct version has already been placed on its path
the versions do match, as far as I can tell
(the base project building first includes:
, so both package versions correspond)
I already have plenty of places in the solution where plugins/subordinate projects exclude runtime and native assets and loading proceeds fine; it is only the single-file case that seems to fail
why are you publishing single file and then trying to un-single-file it?
it was mostly provoked by packages that end up bundling a large amount of satellite assemblies, ex.
System.CommandLine
I strongly prefer not having an additional ~10 folders and ~20 files manifest next to a tool in a already sizable deployment
apart from a breaking change in .NET 10 wrt native library probing (https://learn.microsoft.com/en-us/dotnet/core/compatibility/interop/10.0/native-library-search), I don't see the issue in bundling minor cruft while excluding/loading from PATH large shared dependencies- or how probing should differ for this case
the use case is effectively as in https://github.com/dotnet/sdk/issues/25411#issuecomment-3079299404, although what I want to know at the moment is why library search fails here
I think right now this might be achievable by using ExcludeAssets on shared bits, having a separate project deploy the shared bits, and having some code in the applications set up an ALC that permits the shared bits to be considered for loading.of which I am already doing the first two. Why is the final part required?
i don't think non self contained single file even is supported?
I assumed it is based on https://learn.microsoft.com/en-us/dotnet/core/deploying/single-file/overview?tabs=cli
Single-file deployment is available for both the framework-dependent deployment model and self-contained applications.Or do you mean 'self-contained' in some other sense at the very least I get no build or publish-time warning about it hm. even in a single file app that doesn't
<ExcludeAssets/>
a dependency DLL, the same exact issue manifests if the app loads an assembly outside of the single file
i.e.
which performs:
will throw finding a dependency of the target assembly, although it is all located in the same folder as the single-file application
Morbidly, using:
in the project allows it to work, since https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/default-probing#managed-assembly-default-probing says:
When the *.deps.json file isn't present, the application's directory is assumed to contain all the dependencies. The directory's contents are used to populate the probing properties.but that's a hack and a half. I should be able to somehow hint that it will be found on the path. How does one manipulate these 'probing' properties at build time? Right. I get it now.
<ExcludeAssets>
just purges the associated entries completely from .deps.json
. It's not that it can't find it, it doesn't even try to.
You have to ensure dependencies marked as such are loaded by hand before any usage of their types that would trigger the default probing process. This is what I do in the plugin framework and it works.
I have to mirror this exact thing in the standalone application.
I think it's fairly unintuitive that this means "do not probe at all" rather than "do not ship; it will be already loaded or alongside you"
I suppose only specifying <ExcludeFromSingleFile>
might give valid output, but that doesn't work on PackageReference
s somehow?
It does. Then the DLLs can be removed by force from the bundle using a MSBuild target and it works. Good.