C
C#•2w ago
Emily-TTG

Resolve `dotnet` executable path programmatically

Trying to get NuGet packages loading correctly under a hosted env. -- so I need to grab the NuGet package dir. But doing so programmatically itself seems to require a NuGet package so I'm trying to just grab the output from dotnet nuget locals global-packages --list instead. However I want to try and support a situation where the executing dotnet may not be the one on the PATH, or no dotnet is present on the PATH at all -- so I'd like to grab the dotnet executable which is running the current program. I couldn't find a reliable way to do this without some janky solution like getting the process argv with native APIs so I thought I'd ask here. Thanks in advance!
57 Replies
Emily-TTG
Emily-TTGOP•2w ago
I cant use the NuGet package for NuGet in my process for loading NuGet packages ;p unless I embedded that package in my hosting lib which seems suboptimal no it's a native program loading and running .NET so I've got a ResolveAssembly function which I'm adding to the ALC Resolving within which I need to handle loading user DLLs, and therefore also their dependencies yeah there's no dotnet running the program but there is an associated runtime somewhere on the system I could get the hostfxr library path and work backwards or smth but that would also be a bit jank on Linux we defer to ld.so's mechanisms for loading the hostfxr library since the user could be doing something wacky then have a few default paths as fallback From what I can tell MS just recommends something like this for Windows:
c++
std::filesystem::path basePath = "";

TCHAR pf[MAX_PATH];
SHGetSpecialFolderPath(nullptr, pf, CSIDL_PROGRAM_FILES, FALSE);

basePath = pf;
basePath /= "dotnet/host/fxr/";
c++
std::filesystem::path basePath = "";

TCHAR pf[MAX_PATH];
SHGetSpecialFolderPath(nullptr, pf, CSIDL_PROGRAM_FILES, FALSE);

basePath = pf;
basePath /= "dotnet/host/fxr/";
which also doesn't allow for multi-installs or getting an alternate path but at that point you'd just be asking the user for a path from what I can tell on non-Windows systems the vendor is allowed tell dotnet to go in a load of different prefixes it's certainly not the end of the world to just say "please use a sane environment with a standard install" but as a hosting library that isn't neccesarily a reasonable request before leaving Mono for .NET Core we had a mini Mono root being shipped in an engine f.e. all good -- thanks for pitching in anyway!
wasabi
wasabi•2w ago
Isn't this what nethost is for, or?
Emily-TTG
Emily-TTGOP•2w ago
wdym?
wasabi
wasabi•2w ago
The nethost library. It's job is to locate hostfxr. Unless I'm mistaken, the idea is you use either include the nethost bin, or statically compile it, and that is responsible for locating hostfxr.
Emily-TTG
Emily-TTGOP•2w ago
haven't looked into it but that infra was written before I inherited the lib -- I'll take a gander but irrespective that doesn't really help me with the NuGet paths unless I'm misunderstanding you
wasabi
wasabi•2w ago
Well the NuGet libraries are .NET assemblies..... I think you're going to need to describe the entire problem a lot clearer.
Emily-TTG
Emily-TTGOP•2w ago
okay gimme a sec and I'll reword it I'm working in a .NET hosting env, I'm trying to get loading assemblies which use NuGet packages to work so I need to get the NuGet package path of the relevant SDK that I'm using but that SDK may not necessarily be in a standard location and obviously I can't use the normal programmatic ways to get the paths because they are themselves NuGet packages
wasabi
wasabi•2w ago
Why would there be an SDK at all?
Emily-TTG
Emily-TTGOP•2w ago
so I need to grab the relevant dotnet executable, to get the NuGet package cache well SDK/runtime they run out of the same relative root no?
wasabi
wasabi•2w ago
The part that doesn't make sense to me is that at runtime, an SDK isnt even required to be installed. The .NET runtime itself doesn't make use of Nuget at all. So these nuget packages you're trying to locate, I guess I don't understand why?
Emily-TTG
Emily-TTGOP•2w ago
like if I just dotnet build a .NET project which happens to use NuGet packages -- those packages don't live alongside the project's built artefacts
wasabi
wasabi•2w ago
Right. That's what dotnet publish is for.
Emily-TTG
Emily-TTGOP•2w ago
sure -- but packaging is the responsibility of the application which is using this hosting lib since
wasabi
wasabi•2w ago
It builds a publishable (redistributable) set. Which includes any relevant dependencies.
Emily-TTG
Emily-TTGOP•2w ago
it could have a whole plethora of other run req.s and also to my understanding you don't want to be publishing for every single build?
wasabi
wasabi•2w ago
So, let me try to see if I understand. YOu are getting DLLs from some unknown source, and need to 'include their dependencies'. And want to use NuGet at runtime to do that?
Emily-TTG
Emily-TTGOP•2w ago
at least that's what MSDN made me believe
wasabi
wasabi•2w ago
You don't need to publish if you are just running it out of your dev environment.
Emily-TTG
Emily-TTGOP•2w ago
well yeah but that doesn't currently work not neccesarily use NuGet at runtime -- but if the normal resolution fails
wasabi
wasabi•2w ago
What normal resolution?
Emily-TTG
Emily-TTGOP•2w ago
then try and resolve out of the NuGet runtime paths
wasabi
wasabi•2w ago
The only 'normal resolution' is that specified by deps.json or the ALC by hand.
Emily-TTG
Emily-TTGOP•2w ago
like -- the default relative-to-module DLL loading infra
wasabi
wasabi•2w ago
Yeah. That's why .deps.json exists.
Emily-TTG
Emily-TTGOP•2w ago
yeah, it just doesn't automatically resolve dev packages under the hosting env. for whatever reason
wasabi
wasabi•2w ago
So, okay. This is the issue. You should not be even trying to load individual assemblies form third party sources like that. They need to come with their deps. Barring that, you'd have to reconstruct all that: and you don't and cannot have enough information to truly do that.
Emily-TTG
Emily-TTGOP•2w ago
wdym "come with their deps"? like from running publish?
wasabi
wasabi•2w ago
Say I build a plugin for an app. When distributing the plugin, I would include a .deps.json, and all of the required assemblies. Yup.
Emily-TTG
Emily-TTGOP•2w ago
yeah there is a deps.json which references the relevant package
wasabi
wasabi•2w ago
deps.json doesn't reference packages, actually. That's sort of a holdover from .NET Core 1, when packages.json was a thing.
Emily-TTG
Emily-TTGOP•2w ago
?
No description
wasabi
wasabi•2w ago
Yeah but those need not be actual package IDs. ProjectReferences appear there as a key as well.
Emily-TTG
Emily-TTGOP•2w ago
yeah there's this and a project ref but it fails to automatically resolve the package
wasabi
wasabi•2w ago
Yup Because nuget is out of hte picture at this point.
Emily-TTG
Emily-TTGOP•2w ago
hence why I'm trying to "work backwards" as it were
wasabi
wasabi•2w ago
The .deps.json describes the relative file path to use.
Emily-TTG
Emily-TTGOP•2w ago
but then how can dotnet resolve from the NuGet package with assumedly the same amount of info when running in a dev env? or does it source that from the sln
wasabi
wasabi•2w ago
It doesn't. Again, the dotnet runtime does not use nuget at all. The BUILD does.
Emily-TTG
Emily-TTGOP•2w ago
I think I'm misunderstanding you here -- running a build doesn't appear to copy any dependencies into the bindir
wasabi
wasabi•2w ago
For an EXE it does.
Emily-TTG
Emily-TTGOP•2w ago
ah well uh
wasabi
wasabi•2w ago
And there's a property to turn that on for assemblies.
Emily-TTG
Emily-TTGOP•2w ago
ah I see -- which property would that be?
wasabi
wasabi•2w ago
One sec. Checking. CopyLocalLockFileAssemblies
wasabi
wasabi•2w ago
MSBuild properties for Microsoft.NET.Sdk - .NET
Reference for the MSBuild properties and items that are understood by the .NET SDK.
wasabi
wasabi•2w ago
So the general assumption is that you aren't going to be directly 'running' a DLL output type project. So it speeds up the build by not doing this work (though it is done during publish anyways). (publish on a DLL output type is still how you should do it, imo) In fact it says all that on that page.
Emily-TTG
Emily-TTGOP•2w ago
I mean if publish on every build doesn't have detrimental effects then I can tell users to do that it's just it seemed like that was discouraged
wasabi
wasabi•2w ago
On every release, not on every build. Distinction.
Emily-TTG
Emily-TTGOP•2w ago
but during development you still need the dependency
wasabi
wasabi•2w ago
If you're going to be distributing the DLL outside of the build diretory, etc.
Emily-TTG
Emily-TTGOP•2w ago
like even if you never make a release you still need the dependencies to run the DLL
wasabi
wasabi•2w ago
Well, you don't run DLLs, so you're talking about some separate app doing the running, right? Even at dev time.
Emily-TTG
Emily-TTGOP•2w ago
yeah -- the hosting lib is "running" the DLLs or IG "using" would be more accurate
wasabi
wasabi•2w ago
Yeah. So. You can either turn on copylocklocal, and point the hosting DLL at the bin dir, or add custom MSBuild targets to do the publish. Or come up with some other dev loops.
Emily-TTG
Emily-TTGOP•2w ago
think like a Unity project f.e. -- it builds to DLL then that gets "run" by the Unity runtime ah darn premake doesn't support that property by the looks of things -- time to bother dragonslayer 😅 anyway thank you very much for explaining!
wasabi
wasabi•2w ago
No problem. I went looking btw, and I'm a little doubtful whether any of this can be considered GPLv3 safe the way you want it to be. Hehe.
Emily-TTG
Emily-TTGOP•2w ago
the primary audience for Coral seems to be game engine devs anyway so I think I can live with that ;p Hazel itself already has some wonky licencing we'd need to iron out for a proper release :odileDespair:

Did you find this page helpful?