Skip to content

Commit e4d6fb6

Browse files
authored
fix: make NuGet resolver native-lib preload best-effort (#1)
1 parent 62ab224 commit e4d6fb6

1 file changed

Lines changed: 22 additions & 6 deletions

File tree

sources/shared/Stride.NuGetResolver/NuGetAssemblyResolver.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,15 @@ public static void SetupNuGet(List<(string targetFramework, string packageName,
152152
// Register the native libraries
153153
var nativeLibs = RestoreHelper.ListNativeLibs(result.LockFile);
154154
RegisterNativeDependencies(assemblyNameToPath, nativeLibs);
155-
// FIXME xplat-editor we should have a flag to determine whether native libraries need to be pre-loaded.
156-
// At the moment, we have an issue when using the new editor which forces us to preload all of them (not only Avalonia's native dependencies, but also ours like SDL).
157-
LoadNativeDependencies(assemblyNameToPath, nativeLibs);
155+
// The Avalonia-based GameStudio has a bootstrap chicken-and-egg problem: its native
156+
// dependencies (Avalonia's own, plus ours like SDL) must already be loaded before the
157+
// UI can start, so we eagerly preload every restored native lib here rather than just
158+
// Avalonia's. RegisterNativeDependencies above already wired the DllImport resolver, so
159+
// preloading is only an optimization/bootstrap aid: it is best-effort and a lib that
160+
// can't be preloaded in the current environment (e.g. a headless tool like the asset
161+
// compiler where some libs' transitive deps are absent) is skipped instead of aborting
162+
// the whole restore. The real P/Invoke will still resolve it via the registered path.
163+
LoadNativeDependencies(assemblyNameToPath, nativeLibs, logger);
158164

159165
#if STRIDE_NUGET_RESOLVER_UI
160166
if (packageName == AvaloniaPackageName)
@@ -268,9 +274,10 @@ private static void RegisterNativeDependencies(Dictionary<string, string> assemb
268274
}
269275

270276
/// <summary>
271-
/// Loads the listed native libs in Stride.Core.NativeLibraryHelper using reflection to avoid a compile time dependency on Stride.Core
277+
/// Loads the listed native libs in Stride.Core.NativeLibraryHelper using reflection to avoid a compile time dependency on Stride.Core.
278+
/// Preloading is best-effort: a library that fails to load in the current environment is logged and skipped rather than aborting the restore.
272279
/// </summary>
273-
private static void LoadNativeDependencies(Dictionary<string, string> assemblyNameToPath, List<string> nativeLibs)
280+
private static void LoadNativeDependencies(Dictionary<string, string> assemblyNameToPath, List<string> nativeLibs, Logger logger)
274281
{
275282
var strideCoreAssembly = Assembly.LoadFrom(assemblyNameToPath["Stride.Core"])
276283
?? throw new InvalidOperationException("Couldn't find assembly 'Stride.Core' in restored packages");
@@ -281,7 +288,16 @@ private static void LoadNativeDependencies(Dictionary<string, string> assemblyNa
281288
foreach (var lib in nativeLibs)
282289
{
283290
var libName = Path.GetFileNameWithoutExtension(lib);
284-
preloadLibraryMethod.Invoke(null, [libName, null]);
291+
try
292+
{
293+
preloadLibraryMethod.Invoke(null, [libName, null]);
294+
}
295+
catch (Exception e)
296+
{
297+
// Unwrap the reflection wrapper for a clearer message.
298+
var inner = (e as TargetInvocationException)?.InnerException ?? e;
299+
logger.LogWarning($"Could not preload native library '{libName}' ({inner.GetType().Name}: {inner.Message}). Skipping; it will be resolved on demand if needed.");
300+
}
285301
}
286302
}
287303

0 commit comments

Comments
 (0)