From 688977342774573a18904fde8a291c678fd544db Mon Sep 17 00:00:00 2001 From: Paul Knopf Date: Fri, 12 Apr 2019 23:47:07 -0400 Subject: [PATCH] Simplified the loading of native libs in Qml.Net. This effectively removes support from loading Qt from NuGet. Finalized the ability to configure a Qt runtime directory on Linux. --- src/net/Qml.Net/Internal/Interop.cs | 54 ++-------------------- src/net/Qml.Net/Runtimes/RuntimeManager.cs | 52 +++++++++++++-------- 2 files changed, 38 insertions(+), 68 deletions(-) diff --git a/src/net/Qml.Net/Internal/Interop.cs b/src/net/Qml.Net/Internal/Interop.cs index d513a45e..1bca3d1e 100644 --- a/src/net/Qml.Net/Internal/Interop.cs +++ b/src/net/Qml.Net/Internal/Interop.cs @@ -16,10 +16,6 @@ namespace Qml.Net.Internal static Interop() { - string pluginsDirectory = null; - string qmlDirectory = null; - string libDirectory = null; - IPathResolver pathResolver = null; IPlatformLoader loader = null; @@ -47,42 +43,6 @@ namespace Qml.Net.Internal { pathResolver = new LinuxDllImportLibraryPathResolver(pathResolver); } - - var resolveResult = pathResolver.Resolve("QmlNet"); - - if (resolveResult.IsSuccess) - { - libDirectory = Path.GetDirectoryName(resolveResult.Path); - if (!string.IsNullOrEmpty(libDirectory)) - { - // If this library has a plugins/qml directory below it, set it. - var potentialPlugisDirectory = Path.Combine(libDirectory, "plugins"); - if (Directory.Exists(potentialPlugisDirectory)) - { - pluginsDirectory = potentialPlugisDirectory; - } - - var potentialQmlDirectory = Path.Combine(libDirectory, "qml"); - if (Directory.Exists(potentialQmlDirectory)) - { - qmlDirectory = potentialQmlDirectory; - } - } - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - if (!string.IsNullOrEmpty(libDirectory) && Directory.Exists(libDirectory)) - { - // Even though we opened up the native dll correctly, we need to add - // the folder to the path. The reason is because QML plugins aren't - // in the same directory and have trouble finding dependencies - // that are within our lib folder. - Environment.SetEnvironmentVariable( - "PATH", - Environment.GetEnvironmentVariable("PATH") + $";{libDirectory}"); - } - } } var result = pathResolver.Resolve("QmlNet"); @@ -114,14 +74,10 @@ namespace Qml.Net.Internal QtWebEngine = LoadInteropType(library, loader); QTest = LoadInteropType(library, loader); - if (!string.IsNullOrEmpty(pluginsDirectory)) - { - Qt.PutEnv("QT_PLUGIN_PATH", pluginsDirectory); - } - if (!string.IsNullOrEmpty(qmlDirectory)) - { - Qt.PutEnv("QML2_IMPORT_PATH", qmlDirectory); - } + // RuntimeManager.ConfigureRuntimeDirectory may set these environment variables. + // However, they only really work when called with Qt.PutEnv. + Qt.PutEnv("QT_PLUGIN_PATH", Environment.GetEnvironmentVariable("QT_PLUGIN_PATH")); + Qt.PutEnv("QML2_IMPORT_PATH", Environment.GetEnvironmentVariable("QML2_IMPORT_PATH")); var cb = DefaultCallbacks.Callbacks(); Callbacks.RegisterCallbacks(ref cb); @@ -167,7 +123,7 @@ namespace Qml.Net.Internal public static QTestInterop QTest { get; } - private static T LoadInteropType(IntPtr library, NetNativeLibLoader.Loader.IPlatformLoader loader) + private static T LoadInteropType(IntPtr library, IPlatformLoader loader) where T : new() { var result = new T(); diff --git a/src/net/Qml.Net/Runtimes/RuntimeManager.cs b/src/net/Qml.Net/Runtimes/RuntimeManager.cs index afe34bcb..d835791a 100644 --- a/src/net/Qml.Net/Runtimes/RuntimeManager.cs +++ b/src/net/Qml.Net/Runtimes/RuntimeManager.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using System.Net.Http; using System.Runtime.InteropServices; using System.Threading; @@ -12,21 +13,23 @@ namespace Qml.Net.Runtimes // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global - public static BuildRuntimeUrlDelegate BuildRuntimeUrl = (qtVersion, target) => + public static BuildRuntimeUrlDelegate BuildRuntimeUrl = (qtVersion, target) + => $"https://github.com/qmlnet/qt-runtimes/releases/download/releases/{qtVersion}-{RuntimeTargetToString(target)}-runtime.tar.gz"; + + private static string RuntimeTargetToString(RuntimeTarget target) { - var url = $"https://github.com/qmlnet/qt-runtimes/releases/download/releases/{qtVersion}-{{target}}-runtime.tar.gz"; switch (target) { case RuntimeTarget.Windows64: - return url.Replace("{target}", "win-x64"); + return "win-x64"; case RuntimeTarget.LinuxX64: - return url.Replace("{target}", "linux-x64"); + return "linux-x64"; case RuntimeTarget.OSX64: - return url.Replace("{target}", "osx-x64"); + return "osx-x64"; default: throw new Exception($"Unknown target {target}"); } - }; + } public delegate void ExtractTarGZStreamDelegate(Stream stream, string destinationDirectory); @@ -129,40 +132,51 @@ namespace Qml.Net.Runtimes } var version = File.ReadAllText(versionFile).TrimEnd(Environment.NewLine.ToCharArray()); - var expectedVersion = $"{QmlNetConfig.QtBuildVersion}-{GetCurrentRuntimeTarget()}"; + var expectedVersion = $"{QmlNetConfig.QtBuildVersion}-{RuntimeTargetToString(GetCurrentRuntimeTarget())}"; if (version != expectedVersion) { throw new Exception($"The version of the runtime directory was {versionFile}, but expected {expectedVersion}"); } - var pluginsDirectory = Path.Combine(directory, "plugins"); + var pluginsDirectory = Path.Combine(directory, "qt", "plugins"); if (!Directory.Exists(pluginsDirectory)) { throw new Exception($"Plugins directory didn't exist: {pluginsDirectory}"); } Environment.SetEnvironmentVariable("QT_PLUGIN_PATH", pluginsDirectory); - var qmlDirectory = Path.Combine(directory, "qml"); + var qmlDirectory = Path.Combine(directory, "qt", "qml"); if (!Directory.Exists(qmlDirectory)) { throw new Exception($"QML directory didn't exist: {qmlDirectory}"); } Environment.SetEnvironmentVariable("QML2_IMPORT_PATH", qmlDirectory); - /*if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + var libDirectory = Path.Combine(directory, "qt", "lib"); + if (!Directory.Exists(libDirectory)) { - if (!string.IsNullOrEmpty(libDirectory) && Directory.Exists(libDirectory)) + throw new Exception($"The lib directory didn't exist: {libDirectory}"); + } + + var preloadPath = Path.Combine(libDirectory, "preload.txt"); + if (!File.Exists(preloadPath)) + { + throw new Exception($"The preload.txt file didn't exist: {preloadPath}"); + } + + var libsToPreload = File.ReadAllLines(preloadPath).Where(x => !string.IsNullOrEmpty(x)) + .Select(x => Path.Combine(libDirectory, x)) + .ToList(); + var platformLoader = NetNativeLibLoader.Loader.PlatformLoaderBase.SelectPlatformLoader(); + foreach (var libToPreload in libsToPreload) + { + var libHandler = platformLoader.LoadLibrary(libToPreload); + if (libHandler == IntPtr.Zero) { - // Even though we opened up the native dll correctly, we need to add - // the folder to the path. The reason is because QML plugins aren't - // in the same directory and have trouble finding dependencies - // that are within our lib folder. - Environment.SetEnvironmentVariable( - "PATH", - Environment.GetEnvironmentVariable("PATH") + $";{libDirectory}"); + throw new Exception($"Unabled to preload library: {libToPreload}"); } - }*/ + } } } } \ No newline at end of file