Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core project with native library depedency

I am writing an app in .NET Core that depends on native code using [DllImport]. I have the native compiled library artifacts for win-x64, win-x86, and linux-x64.

My project structure is like:

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

I get then DLL not found exceptions when I run the app.

I have tried to use MSBuild targets solution here, but this only copies one dll to the main output folder at compile time. However, I want to the output to include all three native libraries in the output folder in the same structure as the runtimes folder above, and leave the selection of the compatible native library to .NET Core runtime host.

So if the user runs the app in Windows x86, it will use the win-x86, and so on.

I have noticed when I reference native wrappers like SkiaSharp from NuGet, it will actually integrate nicely into my app, and will include all assets in a runtimes folder structure to work on multiple environments at runtime. How can I do this?

Edit:

I ended up creating a nuget package for the native library binding, and reference the nuget in my other projects.

like image 903
Ghasan غسان Avatar asked Nov 20 '19 13:11

Ghasan غسان


1 Answers

This should copy your folder structure to the output folder, just put it right away under the first </PropertyGroup> in your MyApp.csproj:

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

Just in case, there is a method to have more control on how you are loading the native libraries using DllImport by DllImportResolver delegate for your assembly.

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

There is also NativeLibrary class which allows to set and load native libraries for .net core. Some sample code:

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();
}
like image 178
Andriy Kizym Avatar answered Sep 28 '22 06:09

Andriy Kizym