// Z3NativeLoader.cs - Bibliotheque native de Z3 pour les notebooks C# qui chargent Microsoft.Z3 depuis NuGet // Usage dans un notebook, avant le premier appel a Z3 : // #r "nuget: Microsoft.Z3" // #load "Z3NativeLoader.cs" // Z3NativeLoader.Register(typeof(Microsoft.Z3.Context).Assembly); // // Le paquet NuGet Microsoft.Z3 (4.12.2, derniere version publiee) ne livre la bibliotheque // native que pour Windows x64 et macOS Intel (runtimes/win-x64, runtimes/osx-x64). Ailleurs // (Linux, macOS Apple Silicon), le premier appel a Z3 leve DllNotFoundException 'libz3'. // Ce chargeur indique alors a .NET ou trouver libz3, dans cet ordre : // 1. le dossier designe par Z3_LIBRARY_PATH (la variable que z3-py consulte aussi) ; // 2. le dossier lib/ du paquet Python z3-solver, celui des notebooks Python de la serie // (le premier interpreteur, python3 puis python, qui importe z3) ; // 3. les dossiers systeme (paquet libz3-dev, Homebrew). // Meme moteur que z3-solver. Pour retrouver exactement les sorties committees, prendre // la version du paquet NuGet : pip install z3-solver==4.12.2.0. // Sous Windows et macOS Intel, rien ne change : la bibliotheque du paquet NuGet est utilisee. using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; public static class Z3NativeLoader { static string _path; /// Chemin de la bibliotheque chargee, ou null si celle du paquet NuGet suffit. public static string LoadedFrom => _path; public static void Register(Assembly z3Assembly) { bool nugetHasNative = OperatingSystem.IsWindows() || (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.X64); if (nugetHasNative || _path != null) return; string path = Find(); try { NativeLibrary.SetDllImportResolver(z3Assembly, (name, assembly, searchPath) => name == "libz3" ? NativeLibrary.Load(path) : IntPtr.Zero); } catch (InvalidOperationException) { // cellule re-executee : un resolveur est deja installe sur cet assembly } _path = path; } static string Find() { string file = OperatingSystem.IsMacOS() ? "libz3.dylib" : "libz3.so"; var candidates = new System.Collections.Generic.List(); var env = Environment.GetEnvironmentVariable("Z3_LIBRARY_PATH"); if (!string.IsNullOrEmpty(env)) foreach (var dir in env.Split(Path.PathSeparator)) candidates.Add(Path.Combine(dir, file)); foreach (var exe in new[] { "python3", "python" }) { var dir = Z3SolverLibDir(exe); if (dir != null) { candidates.Add(Path.Combine(dir, file)); break; } } foreach (var dir in new[] { "/usr/lib/x86_64-linux-gnu", "/usr/lib/aarch64-linux-gnu", "/usr/lib64", "/usr/lib", "/usr/local/lib", "/opt/homebrew/lib" }) candidates.Add(Path.Combine(dir, file)); foreach (var c in candidates) if (File.Exists(c)) return c; throw new FileNotFoundException( $"{file} introuvable : le paquet NuGet Microsoft.Z3 ne la livre pas pour cette plateforme. " + "Installer le paquet Python z3-solver (pip install z3-solver==4.12.2.0), " + "ou definir Z3_LIBRARY_PATH vers le dossier qui contient " + file + "."); } // Dossier lib/ du paquet z3-solver vu par cet interpreteur, ou null. static string Z3SolverLibDir(string exe) { try { var psi = new ProcessStartInfo(exe) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false }; psi.ArgumentList.Add("-c"); psi.ArgumentList.Add("import os, z3; print(os.path.join(os.path.dirname(z3.__file__), 'lib'))"); using var p = Process.Start(psi); var stderr = p.StandardError.ReadToEndAsync(); string dir = p.StandardOutput.ReadToEnd().Trim(); p.WaitForExit(); return p.ExitCode == 0 && Directory.Exists(dir) ? dir : null; } catch (System.ComponentModel.Win32Exception) { return null; // interpreteur absent du PATH } } }