Summary
On Ubuntu / Ubuntu-derived distros, Silk.NET 2.22.0's native loader does not probe runtimes/<rid>/native/ for bundled native libraries because the hardcoded _linuxRiDs fallback list in DefaultPathResolver.cs is missing "ubuntu".
The bundled libglfw.so.3 shipped by the Silk.NET NuGet package is therefore unreachable, and Silk.NET.Windowing.Window.Create(...) throws:
System.PlatformNotSupportedException: Couldn't find a suitable window platform.
(GlfwPlatform - not applicable)
at Silk.NET.Windowing.Window.Create(WindowOptions options)
This is the same symptom as #652 (which #661 was supposed to fix). The RuntimesFolderResolver / NativePackageResolver machinery added in #661 is still there in 2.22.0, but it can't reach linux-x64 from ubuntu.24.04-x64 on a modern .NET SDK because of the missing fallback entry.
Environment
- Silk.NET: 2.22.0
- OS: Pop!_OS 24.04 LTS (Ubuntu-based), kernel 6.18.7, x86_64
- .NET SDK: 10.0.107
- Session: Wayland (with XWayland;
DISPLAY=:1)
- Build: framework-dependent
dotnet build (no <RuntimeIdentifier> set, no dotnet publish)
RuntimeEnvironment.GetRuntimeIdentifier() reports: ubuntu.24.04-x64
Root cause (traced through the v2.22.0 source)
In src/Core/Silk.NET.Core/Loader/DefaultPathResolver.cs:
private static readonly string[] _linuxRiDs =
{
"alpine", "android", "arch", "centos", "debian", "exherbo", "fedora", "freebsd", "gentoo", "linux",
"opensuse", "rhel", "sles", "tizen"
};
GuessFallbackRid("ubuntu.24.04-x64") splits on - giving split[0] = "ubuntu.24.04", then runs _linuxRiDs.Any(x => split[0].StartsWith(x)). "ubuntu.24.04" does not start with any of those prefixes ("ubuntu" is missing), so the function returns null.
In GetAllRuntimeIds, that means:
currentRid = "ubuntu.24.04-x64" is added.
AddFallbacks walks ctx.RuntimeGraph for an entry whose Runtime == "ubuntu.24.04-x64". On modern .NET (8+), framework-dependent deps.json files have an empty or minimal runtimes section (RID graphs were largely retired in favor of portable RIDs), so this lookup misses.
GuessFallbackRid is called as the last-resort path → returns null → linux-x64 is never added.
So TryLocateNativeAssetInRuntimesFolder only ever tests runtimes/ubuntu.24.04-x64/native/<libname> (which doesn't exist — NuGet places the assets under the portable RID linux-x64) and TryLocateNativeAssetFromDeps never matches a runtime asset either.
strace evidence
strace -f -e openat of the failing run, filtered to glfw probes, showing zero runtimes/linux-x64/native/ lookups:
openat("/lib/x86_64-linux-gnu/libglfw.so.3.3", ...) = ENOENT
openat("/usr/lib/x86_64-linux-gnu/libglfw.so.3.3", ...) = ENOENT
openat("/lib/libglfw.so.3.3", ...) = ENOENT
openat("/usr/lib/libglfw.so.3.3", ...) = ENOENT
openat("<exe-dir>/libglfw.so.3.3", ...) = ENOENT
openat("/lib/x86_64-linux-gnu/libglfw.so.3", ...) = ENOENT
openat("/usr/lib/x86_64-linux-gnu/libglfw.so.3", ...) = ENOENT
openat("/lib/libglfw.so.3", ...) = ENOENT
openat("/usr/lib/libglfw.so.3", ...) = ENOENT
openat("<exe-dir>/libglfw.so.3", ...) = ENOENT
openat("/lib/x86_64-linux-gnu/libglfw.so", ...) = ENOENT
openat("/usr/lib/x86_64-linux-gnu/libglfw.so", ...) = ENOENT
openat("/lib/libglfw.so", ...) = ENOENT
openat("/usr/lib/libglfw.so", ...) = ENOENT
openat("<exe-dir>/libglfw.so", ...) = ENOENT
The bundled lib is on disk and works:
$ ls <exe-dir>/runtimes/linux-x64/native/libglfw.so.3
<exe-dir>/runtimes/linux-x64/native/libglfw.so.3
$ # dlopen + glfwInit on it returns 1, GLFW 3.4.0 with Wayland + X11 + EGL
Repro
Any project that:
- References
Silk.NET 2.22.0
- Calls
Silk.NET.Windowing.Window.Create(WindowOptions.Default) on Ubuntu / Ubuntu-derived
- Is run from a normal
bin/<config>/<tfm>/ build output (no dotnet publish, no <RuntimeIdentifier>)
Workarounds (confirmed)
Any of these makes it succeed:
LD_LIBRARY_PATH="$PWD/runtimes/linux-x64/native" ./MyApp
- Symlinking/copying
runtimes/linux-x64/native/libglfw.so.3 next to the exe
apt install libglfw3 (so it's found in /usr/lib/x86_64-linux-gnu/)
- Setting
<RuntimeIdentifier>linux-x64</RuntimeIdentifier> in the csproj
Suggested fix
Minimal, low-risk: add "ubuntu" (and probably "pop", "linuxmint") to _linuxRiDs in DefaultPathResolver.cs. That alone unblocks the most common case.
Better fix: when the SDK reports a distro-specific RID like ubuntu.24.04-x64, walk it down to the portable RID linux-x64 directly rather than relying on a hand-maintained distro-prefix list. Modern .NET has been moving toward portable-RID-only for years, so SDK output drifting away from the legacy graph is going to keep happening.
Cross-reference
Summary
On Ubuntu / Ubuntu-derived distros, Silk.NET 2.22.0's native loader does not probe
runtimes/<rid>/native/for bundled native libraries because the hardcoded_linuxRiDsfallback list inDefaultPathResolver.csis missing"ubuntu".The bundled
libglfw.so.3shipped by theSilk.NETNuGet package is therefore unreachable, andSilk.NET.Windowing.Window.Create(...)throws:This is the same symptom as #652 (which #661 was supposed to fix). The
RuntimesFolderResolver/NativePackageResolvermachinery added in #661 is still there in 2.22.0, but it can't reachlinux-x64fromubuntu.24.04-x64on a modern .NET SDK because of the missing fallback entry.Environment
DISPLAY=:1)dotnet build(no<RuntimeIdentifier>set, nodotnet publish)RuntimeEnvironment.GetRuntimeIdentifier()reports:ubuntu.24.04-x64Root cause (traced through the v2.22.0 source)
In
src/Core/Silk.NET.Core/Loader/DefaultPathResolver.cs:GuessFallbackRid("ubuntu.24.04-x64")splits on-givingsplit[0] = "ubuntu.24.04", then runs_linuxRiDs.Any(x => split[0].StartsWith(x))."ubuntu.24.04"does not start with any of those prefixes ("ubuntu"is missing), so the function returnsnull.In
GetAllRuntimeIds, that means:currentRid = "ubuntu.24.04-x64"is added.AddFallbackswalksctx.RuntimeGraphfor an entry whoseRuntime == "ubuntu.24.04-x64". On modern .NET (8+), framework-dependent deps.json files have an empty or minimalruntimessection (RID graphs were largely retired in favor of portable RIDs), so this lookup misses.GuessFallbackRidis called as the last-resort path → returns null →linux-x64is never added.So
TryLocateNativeAssetInRuntimesFolderonly ever testsruntimes/ubuntu.24.04-x64/native/<libname>(which doesn't exist — NuGet places the assets under the portable RIDlinux-x64) andTryLocateNativeAssetFromDepsnever matches a runtime asset either.strace evidence
strace -f -e openatof the failing run, filtered to glfw probes, showing zeroruntimes/linux-x64/native/lookups:The bundled lib is on disk and works:
Repro
Any project that:
Silk.NET2.22.0Silk.NET.Windowing.Window.Create(WindowOptions.Default)on Ubuntu / Ubuntu-derivedbin/<config>/<tfm>/build output (nodotnet publish, no<RuntimeIdentifier>)Workarounds (confirmed)
Any of these makes it succeed:
LD_LIBRARY_PATH="$PWD/runtimes/linux-x64/native" ./MyAppruntimes/linux-x64/native/libglfw.so.3next to the exeapt install libglfw3(so it's found in/usr/lib/x86_64-linux-gnu/)<RuntimeIdentifier>linux-x64</RuntimeIdentifier>in the csprojSuggested fix
Minimal, low-risk: add
"ubuntu"(and probably"pop","linuxmint") to_linuxRiDsinDefaultPathResolver.cs. That alone unblocks the most common case.Better fix: when the SDK reports a distro-specific RID like
ubuntu.24.04-x64, walk it down to the portable RIDlinux-x64directly rather than relying on a hand-maintained distro-prefix list. Modern .NET has been moving toward portable-RID-only for years, so SDK output drifting away from the legacy graph is going to keep happening.Cross-reference
Microsoft.DotNet.PlatformAbstractionsactually returns on newer SDKs