From 35abcc787a6148aa54521a2e5050ea52419d1231 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 16 Oct 2021 17:45:12 -0400 Subject: [PATCH 1/6] Switch to netcoreapp3.1 --- LibGit2Sharp/LibGit2Sharp.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 58c759fa5..95f95a8bb 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netcoreapp2.1 + netstandard2.0;netcoreapp3.1 true LibGit2Sharp brings all the might and speed of libgit2, a native Git implementation, to the managed world of .NET LibGit2Sharp contributors From 2bde4cbf1f2d40bd5dcf674d1ed22fcd60a82c55 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 16 Oct 2021 17:49:57 -0400 Subject: [PATCH 2/6] Use RuntimeInformation.ProcessArchitecture --- LibGit2Sharp/Core/Platform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LibGit2Sharp/Core/Platform.cs b/LibGit2Sharp/Core/Platform.cs index e8d536475..42b752612 100644 --- a/LibGit2Sharp/Core/Platform.cs +++ b/LibGit2Sharp/Core/Platform.cs @@ -12,7 +12,7 @@ internal enum OperatingSystemType internal static class Platform { - public static string ProcessorArchitecture => IntPtr.Size == 8 ? "x64" : "x86"; + public static string ProcessorArchitecture => RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); public static OperatingSystemType OperatingSystem { From b6d3e2f3a9ba79fb42aba9456e6aa8fbdc63a6a8 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 16 Oct 2021 17:51:51 -0400 Subject: [PATCH 3/6] Don't append arch to NativeLibraryPath --- LibGit2Sharp/GlobalSettings.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/LibGit2Sharp/GlobalSettings.cs b/LibGit2Sharp/GlobalSettings.cs index 00b031ca0..d24637df0 100644 --- a/LibGit2Sharp/GlobalSettings.cs +++ b/LibGit2Sharp/GlobalSettings.cs @@ -32,7 +32,7 @@ static GlobalSettings() if (netFX) { // For .NET Framework apps the dependencies are deployed to lib/win32/{architecture} directory - nativeLibraryDefaultPath = Path.Combine(GetExecutingAssemblyDirectory(), "lib", "win32"); + nativeLibraryDefaultPath = Path.Combine(GetExecutingAssemblyDirectory(), "lib", "win32", Platform.ProcessorArchitecture); } else { @@ -159,8 +159,6 @@ public static LogConfiguration LogConfiguration /// /// Sets a path for loading native binaries on .NET Framework or .NET Core. /// When specified, native library will first be searched under the given path. - /// On .NET Framework a subdirectory corresponding to the architecture ("x86" or "x64") is appended, - /// otherwise the native library is expected to be found in the directory as specified. /// /// If the library is not found it will be searched in standard search paths: /// , @@ -170,10 +168,6 @@ public static LogConfiguration LogConfiguration /// This must be set before any other calls to the library, /// and is not available on other platforms than .NET Framework and .NET Core. /// - /// - /// If not specified on .NET Framework it defaults to lib/win32 subdirectory - /// of the directory where this assembly is loaded from. - /// /// public static string NativeLibraryPath { @@ -213,8 +207,7 @@ public static string NativeLibraryPath internal static string GetAndLockNativeLibraryPath() { nativeLibraryPathLocked = true; - string result = nativeLibraryPath ?? nativeLibraryDefaultPath; - return Platform.IsRunningOnNetFramework() ? Path.Combine(result, Platform.ProcessorArchitecture) : result; + return nativeLibraryPath ?? nativeLibraryDefaultPath; } /// From 709a2c80248e055ba13e95a65ec0fa7bbe16336b Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 16 Oct 2021 17:56:20 -0400 Subject: [PATCH 4/6] Use NativeLibrary directly when possible --- LibGit2Sharp/Core/NativeMethods.cs | 73 +++++++----------------------- 1 file changed, 17 insertions(+), 56 deletions(-) diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index 04be0e683..cb5fb45c3 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -30,7 +30,7 @@ static NativeMethods() { if (Platform.IsRunningOnNetFramework() || Platform.IsRunningOnNetCore()) { - // Use .NET Core 3.0+ NativeLibrary when available. + // Use NativeLibrary when available. if (!TryUseNativeLibrary()) { // NativeLibrary is not available, fall back. @@ -40,6 +40,7 @@ static NativeMethods() // If this call succeeds further DllImports will find the library loaded and not attempt to load it again. // If it fails the next DllImport will load the library from safe directories. string nativeLibraryPath = GetGlobalSettingsNativeLibraryPath(); + if (nativeLibraryPath != null) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -61,65 +62,21 @@ static NativeMethods() private static string GetGlobalSettingsNativeLibraryPath() { string nativeLibraryDir = GlobalSettings.GetAndLockNativeLibraryPath(); + if (nativeLibraryDir == null) { return null; } - return Path.Combine(nativeLibraryDir, libgit2 + Platform.GetNativeLibraryExtension()); - } - - private delegate bool TryLoadLibraryByNameDelegate(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, out IntPtr handle); - private delegate bool TryLoadLibraryByPathDelegate(string libraryPath, out IntPtr handle); - - static TryLoadLibraryByNameDelegate _tryLoadLibraryByName; - static TryLoadLibraryByPathDelegate _tryLoadLibraryByPath; - - static bool TryLoadLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, out IntPtr handle) - { - if (_tryLoadLibraryByName == null) - { - throw new NotSupportedException(); - } - return _tryLoadLibraryByName(libraryName, assembly, searchPath, out handle); - } - static bool TryLoadLibrary(string libraryPath, out IntPtr handle) - { - if (_tryLoadLibraryByPath == null) - { - throw new NotSupportedException(); - } - return _tryLoadLibraryByPath(libraryPath, out handle); + return Path.Combine(nativeLibraryDir, libgit2 + Platform.GetNativeLibraryExtension()); } +#if NETSTANDARD + private static bool TryUseNativeLibrary() => false; +#else private static bool TryUseNativeLibrary() { - // NativeLibrary is available in .NET Core 3.0+. - // We use reflection to use NativeLibrary so this library can target 'netstandard2.0'. - - Type dllImportResolverType = Type.GetType("System.Runtime.InteropServices.DllImportResolver, System.Runtime.InteropServices", throwOnError: false); - Type nativeLibraryType = Type.GetType("System.Runtime.InteropServices.NativeLibrary, System.Runtime.InteropServices", throwOnError: false); - var tryLoadLibraryByName = (TryLoadLibraryByNameDelegate)nativeLibraryType?.GetMethod("TryLoad", - new Type[] { typeof(string), typeof(Assembly), typeof(DllImportSearchPath?), typeof(IntPtr).MakeByRefType() })?.CreateDelegate(typeof(TryLoadLibraryByNameDelegate)); - var tryLoadLibraryByPath = (TryLoadLibraryByPathDelegate)nativeLibraryType?.GetMethod("TryLoad", - new Type[] { typeof(string), typeof(IntPtr).MakeByRefType() })?.CreateDelegate(typeof(TryLoadLibraryByPathDelegate)); - MethodInfo setDllImportResolver = nativeLibraryType?.GetMethod("SetDllImportResolver", new Type[] { typeof(Assembly), dllImportResolverType }); - - if (dllImportResolverType == null || - nativeLibraryType == null || - tryLoadLibraryByName == null || - tryLoadLibraryByPath == null || - setDllImportResolver == null) - { - return false; - } - - _tryLoadLibraryByPath = tryLoadLibraryByPath; - _tryLoadLibraryByName = tryLoadLibraryByName; - - // NativeMethods.SetDllImportResolver(typeof(NativeMethods).Assembly, ResolveDll); - object resolveDelegate = typeof(NativeMethods).GetMethod(nameof(ResolveDll), BindingFlags.NonPublic | BindingFlags.Static).CreateDelegate(dllImportResolverType); - setDllImportResolver.Invoke(null, new object[] { typeof(NativeMethods).Assembly, resolveDelegate }); + NativeLibrary.SetDllImportResolver(typeof(NativeMethods).Assembly, ResolveDll); return true; } @@ -127,23 +84,24 @@ private static bool TryUseNativeLibrary() private static IntPtr ResolveDll(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) { IntPtr handle = IntPtr.Zero; + if (libraryName == libgit2) { // Use GlobalSettings.NativeLibraryPath when set. string nativeLibraryPath = GetGlobalSettingsNativeLibraryPath(); - if (nativeLibraryPath != null && - TryLoadLibrary(nativeLibraryPath, out handle)) + + if (nativeLibraryPath != null && NativeLibrary.TryLoad(nativeLibraryPath, out handle)) { return handle; } // Use Default DllImport resolution. - if (TryLoadLibrary(libraryName, assembly, searchPath, out handle)) + if (NativeLibrary.TryLoad(libraryName, assembly, searchPath, out handle)) { return handle; } - // We cary a number of .so files for Linux which are linked against various + // We carry a number of .so files for Linux which are linked against various // libc/OpenSSL libraries. Try them out. if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { @@ -158,7 +116,8 @@ private static IntPtr ResolveDll(string libraryName, Assembly assembly, DllImpor foreach (var runtimeFolder in Directory.GetDirectories(runtimesDirectory, $"*-{processorArchitecture}")) { string libPath = Path.Combine(runtimeFolder, "native", $"lib{libraryName}.so"); - if (TryLoadLibrary(libPath, out handle)) + + if (NativeLibrary.TryLoad(libPath, out handle)) { return handle; } @@ -166,8 +125,10 @@ private static IntPtr ResolveDll(string libraryName, Assembly assembly, DllImpor } } } + return handle; } +#endif public const int RTLD_NOW = 0x002; From 3e78e83b0123f920e0a0448d684b67c61fcebd85 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 16 Oct 2021 17:59:37 -0400 Subject: [PATCH 5/6] Clean up unneeded pragmas --- LibGit2Sharp/Core/NativeMethods.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index cb5fb45c3..809a77309 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -9,9 +9,6 @@ // Restrict the set of directories where the native library is loaded from to safe directories. [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.ApplicationDirectory | DllImportSearchPath.SafeDirectories)] -#pragma warning disable IDE1006 // Naming Styles - -// ReSharper disable InconsistentNaming namespace LibGit2Sharp.Core { internal static class NativeMethods @@ -22,9 +19,7 @@ internal static class NativeMethods // An object tied to the lifecycle of the NativeMethods static class. // This will handle initialization and shutdown of the underlying // native library. -#pragma warning disable 0414 private static NativeShutdownObject shutdownObject; -#pragma warning restore 0414 static NativeMethods() { @@ -2071,4 +2066,3 @@ internal static extern unsafe int git_worktree_prune( git_worktree_prune_options options); } } -// ReSharper restore InconsistentNaming From 9a9a297ee49df921ba7e3268de3ff2279f0f79bd Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Sat, 16 Oct 2021 18:41:46 -0400 Subject: [PATCH 6/6] Update tests --- LibGit2Sharp.Tests/GlobalSettingsFixture.cs | 8 +++++--- NativeLibraryLoadTestApp/TestApp.cs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs index 55260a6f5..8f1aa9d0b 100644 --- a/LibGit2Sharp.Tests/GlobalSettingsFixture.cs +++ b/LibGit2Sharp.Tests/GlobalSettingsFixture.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Reflection; using System.Text.RegularExpressions; using LibGit2Sharp.Core; using LibGit2Sharp.Tests.TestHelpers; @@ -64,12 +65,13 @@ public void LoadFromSpecifiedPath(string architecture) var testDir = Path.GetDirectoryName(typeof(GlobalSettingsFixture).Assembly.Location); var testAppExe = Path.Combine(testDir, $"NativeLibraryLoadTestApp.{architecture}.exe"); var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - var platformDir = Path.Combine(tempDir, "plat"); + var platformDir = Path.Combine(tempDir, "plat", architecture); + var libraryPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "lib", "win32", architecture); try { - Directory.CreateDirectory(Path.Combine(platformDir, architecture)); - File.Copy(Path.Combine(GlobalSettings.NativeLibraryPath, architecture, nativeDllFileName), Path.Combine(platformDir, architecture, nativeDllFileName)); + Directory.CreateDirectory(platformDir); + File.Copy(Path.Combine(libraryPath, nativeDllFileName), Path.Combine(platformDir, nativeDllFileName)); var (output, exitCode) = ProcessHelper.RunProcess(testAppExe, arguments: $@"{NativeDllName.Name} ""{platformDir}""", workingDirectory: tempDir); diff --git a/NativeLibraryLoadTestApp/TestApp.cs b/NativeLibraryLoadTestApp/TestApp.cs index 234169a75..6a9f3ab60 100644 --- a/NativeLibraryLoadTestApp/TestApp.cs +++ b/NativeLibraryLoadTestApp/TestApp.cs @@ -11,7 +11,7 @@ public class TestApp private static extern IntPtr GetModuleHandle(string path); [DllImport("kernel32")] - private static extern int GetModuleFileName(IntPtr handle, [Out]StringBuilder path, int size); + private static extern int GetModuleFileName(IntPtr handle, [Out] StringBuilder path, int size); static int Main(string[] args) { @@ -23,7 +23,7 @@ static int Main(string[] args) var moduleName = args[0]; var loadFromDirectory = args[1]; - var expectedPath = Path.Combine(loadFromDirectory, (IntPtr.Size == 4) ? "x86" : "x64", moduleName + ".dll"); + var expectedPath = Path.Combine(loadFromDirectory, moduleName + ".dll"); GlobalSettings.NativeLibraryPath = loadFromDirectory; var isValid = Repository.IsValid(Path.GetTempPath());