具有本机库依赖项的 .NET Core 项目

.NET Core project with native library depedency

我正在使用 [DllImport] 在 .NET Core 中编写一个依赖本机代码的应用程序。我有 win-x64、win-x86 和 linux-x64 的本机编译库工件。

我的项目结构如下:

MyApp
|--Main.cs
|--runtimes
   |--win-x86
      |--native
         |--somelibrary.dll
   |--win-x64
      |--native
         |--somelibrary.dll
   |--linux-x64
      |--native
         |--libsomelibrary.so

当我 运行 应用程序时,我发现 DLL 未找到异常。

我曾尝试使用 MSBuild 目标解决方案 ,但这只会在编译时将一个 dll 复制到主输出文件夹。但是,我希望输出以与上面 运行times 文件夹相同的结构在输出文件夹中包含所有三个本机库,并将兼容本机库的选择留给 .NET Core 运行时间主持.

因此,如果用户 运行 在 Windows x86 中使用应用程序,它将使用 win-x86,依此类推。

我注意到,当我从 NuGet 中引用 SkiaSharp 等原生包装器时,它实际上会很好地集成到我的应用程序中,并将所有资产包含在 运行 次文件夹结构中以处理多个运行 时间的环境。我该怎么做?

编辑:

我最终为本机库绑定创建了一个 nuget 包,并在我的其他项目中引用了该 nuget。

由于您没有提供任何代码片段来显示您对 DllImportAttribute 的使用或您的应用程序可能执行的任何其他环境初始化,因此很难猜测究竟是什么地方出了问题.

根据现有信息,最有可能的罪魁祸首只是 P/Invoke 系统不知道如何找到您的本机库。您的代码库是否有某种机制可以将搜索路径添加到运行时?或者您是否有机会使用 custom load context?

这应该将您的文件夹结构复制到输出文件夹,只需将其立即放在 MyApp.csproj 中的第一个 </PropertyGroup> 下即可:

<ItemGroup>
    <None Update="runtimes\**" CopyToOutputDirectory="PreserveNewest"/>
</ItemGroup>

以防万一,有一种方法可以通过 DllImportResolver 委托为程序集使用 DllImport 来更好地控制如何加载本机库。

public delegate IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath);

还有 NativeLibrary class 允许为 .net 核心设置和加载本机库。一些示例代码:

static class Sample
{
    const string NativeLib = "NativeLib";

    static Sample()
    {
        NativeLibrary.SetDllImportResolver(typeof(Sample).Assembly, ImportResolver);
    }

    private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
    {
        IntPtr libHandle = IntPtr.Zero;
        //you can add here different loading logic
        if (libraryName == NativeLib && RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.Is64BitProcess)
        {
            NativeLibrary.TryLoad("./runtimes/win-x64/native/somelib.dll", out libHandle);
        } else 
        if (libraryName == NativeLib)
        {
            NativeLibrary.TryLoad("libsomelibrary.so", assembly, DllImportSearchPath.ApplicationDirectory, out libHandle);
        }
        return libHandle;
    }

    [DllImport(NativeLib)]
    public static extern int DoSomework();
}