diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1f15db7..47d90467 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,10 +19,6 @@ jobs: - os: ubuntu-22.04 container: mcr.microsoft.com/dotnet/sdk:8.0-alpine3.18 script: ./build.sh - # TODO(kleisauke): Re-enable Mono CI when C# 9 features are supported. - # - os: ubuntu-22.04 - # script: ./build/test-mono.sh - # allow_failures: true - os: macos-12 script: ./build.sh - os: windows-2022 diff --git a/README.md b/README.md index ca78c693..02f0147f 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,7 @@ which gives some more background. ## Supported platforms - .NET Framework 4.5.2 and higher -- .NET Standard 2.0 and higher -- Mono +- .NET 6.0 and higher ## Install diff --git a/build/Build.cs b/build/Build.cs index 5f127d12..6d8ffd29 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -132,21 +132,10 @@ protected override void OnBuildInitialized() .DependsOn(Clean) .Executes(() => { - // Need to build the macOS and *nix DLL first. - DotNetBuild(c => c - .SetProjectFile(Solution.NetVips) - .SetConfiguration(Configuration) - .SetFramework("netstandard2.0") - .AddProperty("Platform", "AnyCPU") - .CombineWith( - new[] { "OSX", "Unix" }, - (_, os) => _.AddProperty("TargetOS", os))); - DotNetPack(c => c .SetProject(Solution.NetVips) .SetConfiguration(Configuration) .SetOutputDirectory(ArtifactsDirectory) - .AddProperty("TargetOS", "Windows") ); }); diff --git a/build/native/NetVips.Native.linux-arm.nuspec b/build/native/NetVips.Native.linux-arm.nuspec index 72caaec9..0451a10c 100644 --- a/build/native/NetVips.Native.linux-arm.nuspec +++ b/build/native/NetVips.Native.linux-arm.nuspec @@ -22,9 +22,6 @@ - - - @@ -35,7 +32,7 @@ - + \ No newline at end of file diff --git a/build/native/NetVips.Native.linux-arm64.nuspec b/build/native/NetVips.Native.linux-arm64.nuspec index 5d0ab745..851791d1 100644 --- a/build/native/NetVips.Native.linux-arm64.nuspec +++ b/build/native/NetVips.Native.linux-arm64.nuspec @@ -22,9 +22,6 @@ - - - @@ -35,7 +32,7 @@ - + \ No newline at end of file diff --git a/build/native/NetVips.Native.linux-musl-arm64.nuspec b/build/native/NetVips.Native.linux-musl-arm64.nuspec index 55078f30..ee36a3ae 100644 --- a/build/native/NetVips.Native.linux-musl-arm64.nuspec +++ b/build/native/NetVips.Native.linux-musl-arm64.nuspec @@ -32,8 +32,7 @@ - - + \ No newline at end of file diff --git a/build/native/NetVips.Native.linux-musl-x64.nuspec b/build/native/NetVips.Native.linux-musl-x64.nuspec index cb10a20e..ae087d69 100644 --- a/build/native/NetVips.Native.linux-musl-x64.nuspec +++ b/build/native/NetVips.Native.linux-musl-x64.nuspec @@ -22,9 +22,6 @@ - - - @@ -35,7 +32,7 @@ - + \ No newline at end of file diff --git a/build/native/NetVips.Native.linux-x64.nuspec b/build/native/NetVips.Native.linux-x64.nuspec index 044dd606..caa04483 100644 --- a/build/native/NetVips.Native.linux-x64.nuspec +++ b/build/native/NetVips.Native.linux-x64.nuspec @@ -22,9 +22,6 @@ - - - @@ -35,7 +32,7 @@ - + \ No newline at end of file diff --git a/build/native/NetVips.Native.nuspec b/build/native/NetVips.Native.nuspec index 2e157b2e..b655f72b 100644 --- a/build/native/NetVips.Native.nuspec +++ b/build/native/NetVips.Native.nuspec @@ -21,33 +21,20 @@ - - + - - - - - - - - - - - - - + diff --git a/build/native/NetVips.Native.osx-arm64.nuspec b/build/native/NetVips.Native.osx-arm64.nuspec index 299280d1..74bf7cd9 100644 --- a/build/native/NetVips.Native.osx-arm64.nuspec +++ b/build/native/NetVips.Native.osx-arm64.nuspec @@ -32,8 +32,7 @@ - - + \ No newline at end of file diff --git a/build/native/NetVips.Native.osx-x64.nuspec b/build/native/NetVips.Native.osx-x64.nuspec index 799d6e04..ce4a5866 100644 --- a/build/native/NetVips.Native.osx-x64.nuspec +++ b/build/native/NetVips.Native.osx-x64.nuspec @@ -22,9 +22,6 @@ - - - @@ -35,7 +32,7 @@ - + \ No newline at end of file diff --git a/build/native/NetVips.Native.win-arm64.nuspec b/build/native/NetVips.Native.win-arm64.nuspec index 190a4722..b9d39acf 100644 --- a/build/native/NetVips.Native.win-arm64.nuspec +++ b/build/native/NetVips.Native.win-arm64.nuspec @@ -32,8 +32,7 @@ - - + \ No newline at end of file diff --git a/build/native/NetVips.Native.win-x64.nuspec b/build/native/NetVips.Native.win-x64.nuspec index 1be73f0b..3ff799a0 100644 --- a/build/native/NetVips.Native.win-x64.nuspec +++ b/build/native/NetVips.Native.win-x64.nuspec @@ -22,8 +22,8 @@ - - + + diff --git a/build/native/NetVips.Native.win-x86.nuspec b/build/native/NetVips.Native.win-x86.nuspec index 4c208d2a..3d53872a 100644 --- a/build/native/NetVips.Native.win-x86.nuspec +++ b/build/native/NetVips.Native.win-x86.nuspec @@ -22,8 +22,8 @@ - - + + diff --git a/build/native/targets/NetVips.Native.linux-arm.targets b/build/native/targets/NetVips.Native.linux-arm.targets deleted file mode 100644 index 242b3a50..00000000 --- a/build/native/targets/NetVips.Native.linux-arm.targets +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - $(LibvipsOutputBase)\ - - - - - - $(LibvipsOutputBase)%(Filename)%(Extension) - PreserveNewest - - - - \ No newline at end of file diff --git a/build/native/targets/NetVips.Native.linux-arm64.targets b/build/native/targets/NetVips.Native.linux-arm64.targets deleted file mode 100644 index 62c13e13..00000000 --- a/build/native/targets/NetVips.Native.linux-arm64.targets +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - $(LibvipsOutputBase)\ - - - - - - $(LibvipsOutputBase)%(Filename)%(Extension) - PreserveNewest - - - - \ No newline at end of file diff --git a/build/native/targets/NetVips.Native.linux-musl-x64.targets b/build/native/targets/NetVips.Native.linux-musl-x64.targets deleted file mode 100644 index 84c5c801..00000000 --- a/build/native/targets/NetVips.Native.linux-musl-x64.targets +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - $(LibvipsOutputBase)\ - - - - - - $(LibvipsOutputBase)%(Filename)%(Extension) - PreserveNewest - - - - \ No newline at end of file diff --git a/build/native/targets/NetVips.Native.linux-x64.targets b/build/native/targets/NetVips.Native.linux-x64.targets deleted file mode 100644 index 1696b03c..00000000 --- a/build/native/targets/NetVips.Native.linux-x64.targets +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - $(LibvipsOutputBase)\ - - - - - - $(LibvipsOutputBase)%(Filename)%(Extension) - PreserveNewest - - - - \ No newline at end of file diff --git a/build/native/targets/NetVips.Native.osx-x64.targets b/build/native/targets/NetVips.Native.osx-x64.targets deleted file mode 100644 index 60abfd51..00000000 --- a/build/native/targets/NetVips.Native.osx-x64.targets +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - $(LibvipsOutputBase)\ - - - - - - $(LibvipsOutputBase)%(Filename)%(Extension) - PreserveNewest - - - - \ No newline at end of file diff --git a/build/test-mono.sh b/build/test-mono.sh deleted file mode 100755 index 7265bd1f..00000000 --- a/build/test-mono.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -set -eo pipefail - -########################################################################### -# CONFIGURATION -########################################################################### - -BUILD_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) -SCRIPT_DIR=$(dirname "$BUILD_DIR") - -XUNIT_RUNNER="$SCRIPT_DIR/packages/xunit.runner.console/tools/net472/xunit.console.exe" -BUILD_PROJECT_FILE="$SCRIPT_DIR/tests/NetVips.Tests/NetVips.Tests.csproj" -DLL_FILE="$SCRIPT_DIR/tests/NetVips.Tests/bin/Release/net472/NetVips.Tests.dll" - -# https://github.com/dotnet/runtime/issues/11540 -if [ "$(uname)" == "Darwin" ]; then - export DYLD_LIBRARY_PATH=$(dirname "$DLL_FILE")${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH} -elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - export LD_LIBRARY_PATH=$(dirname "$DLL_FILE")${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} -fi - -# Parse arguments -while [ $# -gt 0 ]; do - case $1 in - --global-vips) USE_NUGET_BINARIES=false ;; - *) echo "Unknown parameter passed: $1" >&2; exit 1 ;; - esac - shift -done - -########################################################################### -# EXECUTION -########################################################################### - -if ! [ -x "$(command -v mono)" ]; then - echo 'Error: mono is not installed.' >&2 - exit 1 -fi - -echo "Mono version $(mono --version)" - -nuget install xunit.runner.console -ExcludeVersion -o packages -msbuild $BUILD_PROJECT_FILE -t:build -restore -p:TargetFramework="net472" -p:Configuration=Release -p:TestWithNuGetBinaries=${USE_NUGET_BINARIES:-true} -nodeReuse:false -mono $XUNIT_RUNNER $DLL_FILE diff --git a/src/NetVips.Extensions/NetVips.Extensions.csproj b/src/NetVips.Extensions/NetVips.Extensions.csproj index 278d7901..feaadd92 100644 --- a/src/NetVips.Extensions/NetVips.Extensions.csproj +++ b/src/NetVips.Extensions/NetVips.Extensions.csproj @@ -3,8 +3,8 @@ - net6.0;netstandard2.0;net461 - netstandard2.0 + net6.0;net461 + net6.0 true NetVips.Extensions NetVips.Extensions @@ -20,17 +20,10 @@ - + - - - - - diff --git a/src/NetVips/Interop/Libraries.OSX.cs b/src/NetVips/Interop/Libraries.OSX.cs deleted file mode 100644 index 572edcf2..00000000 --- a/src/NetVips/Interop/Libraries.OSX.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace NetVips.Interop -{ - internal static partial class Libraries - { - // We can safely define all these variables as `libvips.42.dylib` since - // DLLImport uses dlsym() on macOS. This function also searches for named - // symbols in the dependencies of the shared library. Therefore, we can - // provide libvips as a single shared library with all dependencies - // statically linked without breaking compatibility with shared builds - // (i.e. what is usually installed via package managers). - internal const string GLib = "libvips.42.dylib", - GObject = "libvips.42.dylib", - Vips = "libvips.42.dylib"; - } -} \ No newline at end of file diff --git a/src/NetVips/Interop/Libraries.Unix.cs b/src/NetVips/Interop/Libraries.Unix.cs deleted file mode 100644 index 93d2e274..00000000 --- a/src/NetVips/Interop/Libraries.Unix.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace NetVips.Interop -{ - internal static partial class Libraries - { - // We can safely define all these variables as `libvips.so.42` since - // DLLImport uses dlsym() on *nix. This function also searches for named - // symbols in the dependencies of the shared library. Therefore, we can - // provide libvips as a single shared library with all dependencies - // statically linked without breaking compatibility with shared builds - // (i.e. what is usually installed via package managers). - internal const string GLib = "libvips.so.42", - GObject = "libvips.so.42", - Vips = "libvips.so.42"; - } -} \ No newline at end of file diff --git a/src/NetVips/Interop/Libraries.Windows.cs b/src/NetVips/Interop/Libraries.Windows.cs deleted file mode 100644 index 002daed4..00000000 --- a/src/NetVips/Interop/Libraries.Windows.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace NetVips.Interop -{ - internal static partial class Libraries - { - // We cannot define all these variables as `libvips-42.dll` without - // breaking compatibility with the shared Windows build. Therefore, - // we always ship at least 3 DLLs. - internal const string GLib = "libglib-2.0-0.dll", - GObject = "libgobject-2.0-0.dll", - Vips = "libvips-42.dll"; - } -} \ No newline at end of file diff --git a/src/NetVips/Interop/Libraries.cs b/src/NetVips/Interop/Libraries.cs new file mode 100644 index 00000000..dcb80b4a --- /dev/null +++ b/src/NetVips/Interop/Libraries.cs @@ -0,0 +1,13 @@ +namespace NetVips.Interop +{ + internal static class Libraries + { + /// + /// These library names are remapped in a cross-platform manner, + /// . + /// + internal const string GLib = "libglib-2.0-0.dll", + GObject = "libgobject-2.0-0.dll", + Vips = "libvips-42.dll"; + } +} \ No newline at end of file diff --git a/src/NetVips/ModuleInitializer.cs b/src/NetVips/ModuleInitializer.cs index 43b184b0..e428d4c7 100644 --- a/src/NetVips/ModuleInitializer.cs +++ b/src/NetVips/ModuleInitializer.cs @@ -1,6 +1,10 @@ namespace NetVips { using System; + using System.Reflection; + using System.Collections.Generic; + using System.Runtime.InteropServices; + using Interop; /// /// All code inside the method is ran as soon as the assembly is loaded. @@ -22,12 +26,75 @@ public static class ModuleInitializer /// public static int? Version; +#if NET6_0_OR_GREATER + /// + /// Windows specific: is GLib statically-linked in `libvips-42.dll`? + /// + [System.Runtime.Versioning.SupportedOSPlatform("windows")] + private static bool _gLibStaticallyLinked = true; + + /// + /// A cache for . + /// + internal static readonly Dictionary DllImportCache = + new Dictionary(); + + internal static string RemapLibraryName(string libraryName) + { + // For Windows, we try to locate the GLib symbols within + // `libvips-42.dll` first. If these symbols cannot be found there, + // we proceed to locate them within `libglib-2.0-0.dll` and + // `libgobject-2.0-0.dll`. Note that distributing a single shared + // library is only possible when we drop support for .NET Framework. + // Therefore, we always ship at least 3 DLLs for now. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return _gLibStaticallyLinked ? Libraries.Vips : libraryName; + } + + // We can safely remap the library names to `libvips.so.42` on *nix + // and `libvips.42.dylib` on macOS since DLLImport uses dlsym() there. + // This function also searches for named symbols in the dependencies + // of the shared library. Therefore, we can provide libvips as a + // single shared library with all dependencies statically linked + // without breaking compatibility with the shared builds + // (i.e. what is usually installed via package managers). + return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) + ? "libvips.42.dylib" + : "libvips.so.42"; + } + + internal static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) + { + libraryName = RemapLibraryName(libraryName); + if (DllImportCache.TryGetValue(libraryName, out var cachedHandle)) + { + return cachedHandle; + } + + if (NativeLibrary.TryLoad(libraryName, assembly, searchPath, out var handle)) + { + DllImportCache[libraryName] = handle; + return handle; + } + + // Fallback to the default import resolver. + return IntPtr.Zero; + } +#endif + /// /// Initializes the module. /// +#pragma warning disable CA2255 [System.Runtime.CompilerServices.ModuleInitializer] +#pragma warning restore CA2255 public static void Initialize() { +#if NET6_0_OR_GREATER + NativeLibrary.SetDllImportResolver(typeof(ModuleInitializer).Assembly, DllImportResolver); +#endif + try { VipsInitialized = NetVips.Init(); @@ -36,6 +103,19 @@ public static void Initialize() Version = NetVips.Version(0, false); Version = (Version << 8) + NetVips.Version(1, false); Version = (Version << 8) + NetVips.Version(2, false); + +#if NET6_0_OR_GREATER + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return; + + try + { + _gLibStaticallyLinked = NetVips.TypeFromName("VipsImage") != IntPtr.Zero; + } + catch + { + _gLibStaticallyLinked = false; + } +#endif } else { diff --git a/src/NetVips/ModuleInitializerAttribute.cs b/src/NetVips/ModuleInitializerAttribute.cs index 47e805e2..06d6cea3 100644 --- a/src/NetVips/ModuleInitializerAttribute.cs +++ b/src/NetVips/ModuleInitializerAttribute.cs @@ -1,6 +1,6 @@ -// This file enables ModuleInitializer, a C# 9 feature to work with .NET Standard/Framework. +// This file enables ModuleInitializer, a C# 9 feature to work with .NET Framework. -#if NETSTANDARD || NETFRAMEWORK +#if NETFRAMEWORK namespace System.Runtime.CompilerServices { /// diff --git a/src/NetVips/NetVips.csproj b/src/NetVips/NetVips.csproj index 0410589b..d2c763e9 100644 --- a/src/NetVips/NetVips.csproj +++ b/src/NetVips/NetVips.csproj @@ -3,56 +3,26 @@ - netstandard2.0;net452 - netstandard2.0 + net6.0;net452 + net6.0 true Library x64;x86;ARM64;ARM32 true - $(DefaultItemExcludes);Interop\Libraries.*.cs false - false true true - - - Unix - OSX - Windows - - - - - $(MSBuildThisFileDirectory)bin\$(Platform)\$(Configuration)\$(TargetFramework)\$(TargetOS) - $(BaseIntermediateOutputPath)\$(Platform)\$(Configuration)\$(TargetFramework)\$(TargetOS)\ - - - - Interop\Libraries.cs - - + - - - - true - runtimes\unix\lib\netstandard2.0 - - - true - runtimes\osx\lib\netstandard2.0 - - - \ No newline at end of file diff --git a/tests/NetVips.Tests/NetVips.Tests.csproj b/tests/NetVips.Tests/NetVips.Tests.csproj index 15170970..ebeb15e7 100644 --- a/tests/NetVips.Tests/NetVips.Tests.csproj +++ b/tests/NetVips.Tests/NetVips.Tests.csproj @@ -14,30 +14,15 @@ false - - - linux-x64 - osx-x64 - - - - - - - - - - - - - + all runtime; build; native; contentfiles; analyzers; buildtransitive +