From 115a6f0fcc7247b57195f862982959482b518003 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Fri, 3 Apr 2026 01:10:06 +0800 Subject: [PATCH] fix: work around Consolonia libcoreclr.so DllNotFoundException on Linux single-file publish Consolonia's Unix.Terminal uses [DllImport("libcoreclr.so")] to load dlopen/dlsym on .NET Core. It ships a SetDllImportResolver that maps the library name to the current process handle, but the resolver is guarded by #if NET6_0 (exact TFM match) instead of NET6_0_OR_GREATER. Since Consolonia targets net8.0, the resolver is never compiled in. On self-contained single-file publishes, libcoreclr.so is bundled inside the host binary and does not exist on disk. Without the resolver the OS linker cannot find it, causing a DllNotFoundException that crashes the TUI on startup. This primarily affects ARM64 Linux users (e.g. Raspberry Pi / Debian Trixie) who almost exclusively use self-contained publishes. This commit registers an AssemblyLoadContext.Default.ResolvingUnmanagedDll handler in Program.Main (before TUI init) that returns (IntPtr)(-1) for libcoreclr.so, which the runtime interprets as the current process. This is a temporary workaround until the upstream fix lands: https://github.com/Consolonia/Consolonia/pull/605 Made-with: Cursor --- MinecraftClient/Program.cs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index 9e71ad8e..6f505644 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -4,6 +4,8 @@ using System.Globalization; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Loader; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -174,6 +176,9 @@ namespace MinecraftClient }; // --- Determine console mode and initialize backend --- + if (!OperatingSystem.IsWindows()) + InstallCursesNativeResolver(); + if (!ConsoleIO.BasicIO && Config.Console.General.ConsoleMode == ConsoleModeType.tui) { ConsoleIO.Backend?.Shutdown(); @@ -206,6 +211,26 @@ namespace MinecraftClient RunStartupSequence(args); } + /// + /// Consolonia's Unix.Terminal uses [DllImport("libcoreclr.so")] to reach + /// dlopen/dlsym on .NET Core. The library ships a + /// SetDllImportResolver that maps libcoreclr.so to the current + /// process, but it is compiled under #if NET6_0 (exact TFM match) instead + /// of NET6_0_OR_GREATER, so it is dead code when the consuming project + /// targets net8.0+. On a self-contained single-file publish the physical + /// libcoreclr.so does not exist on the search path, causing a + /// DllNotFoundException that crashes the TUI. + /// + /// We work around this by registering our own resolver before any Consolonia + /// code runs: if any assembly asks for libcoreclr.so we return + /// (IntPtr)(-1) which the runtime interprets as "the current process". + /// + private static void InstallCursesNativeResolver() + { + AssemblyLoadContext.Default.ResolvingUnmanagedDll += (assembly, libraryName) => + libraryName == "libcoreclr.so" ? (IntPtr)(-1) : IntPtr.Zero; + } + private static void HandleTuiStartupFailure(Exception exception) { Config.Console.General.ConsoleMode = ConsoleModeType.classic;