Call matlab shared library from dotnet core on linux
Asked Answered
T

2

12

I am trying to call a shared library created with MathWorks MATLAB Compiler SDK from C# (.NET Core) running on a Linux container.

I have a matlab .m file that I've compiled into a .dll using the MATLAB R2018b compiler SDK. Because the final execution environment is .NET Core 2.2 running on a Linux container I chose the "C Shared Library" option. I call that shared library using the DLLImport mechanism of .NET.

Here is some code from my project. This code is KISS-level because I need to understand how to integrate MATLAB and C# on Linux before I start on the main project.

haveSomePi.m

function hal = haveSomePi()
    hal = 3.1415;
end

MyMath.h

extern LIB_MyMath_C_API bool MW_CALL_CONV mlfHaveSomePi(int nargout, mxArray** hal);

MyMathWrapper.cs

[DllImport("MyMath.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mlfHaveSomePi(int nargout, ref IntPtr hal);

MyMathWrapperTests.cs

[TestMethod]
public void ShouldReturnPi()
{
    var hal = IntPtr.Zero;

    MyMathWrapper.mlfHaveSomePi(1, ref hal);

    double result = (double)hal; 

    Assert.AreEqual(3.1415, result, 1e-5);
}

The expected result is that the assert in the test method passes. It fails because trying to cast an IntPtr to a double doesn't make sense in this context. I'm sure there is a way to de-reference the IntPtr to get at the underlying double, I just haven't found that particular nugget of information.

I have been successful when compiling the .m file into a .NET library and into a COM object. I don't think I can use either of those libraries on Linux because of differences in the binary load/link format for each OS. When calling the method in the COM object I was able to directly cast the IntPtr to a double, there must be some marshaling magic going on in the background.

  1. Is the method signature for the DLLImport statement correct? Do I map mxArray** to IntPtr?
  2. How do I get the double from the IntPtr? Copy a block of memory into a managed byte array and cast?

My ultimate goal is to access a large signal processing library of matlab code from dotnet. The matlab code uses a lot of vectors and arrays so getting those into and out of the unmangaged library is my next hurdle.

Best regards.

Thetis answered 26/1, 2019 at 14:6 Comment(6)
Did you try using out keyword instead of ref one?Debar
Yes I did. Because I initialized the variable to IntPtr.Zero, there was no difference in behavior.Thetis
Wow, complex environment, lots of tools. Did you managed to achieve the same goal on Win? would container or VM make a difference? You build everything on Win, and then copy the .dlls on Lnx? What does mlfHaveSomePi implementation look like (trying to see if MATLAB can be excluded)?Asyndeton
you will not be able to use that dll on linux. binaries are different. you'll have to export it on linux somehow or covert your code to C (matlab coder?) so you can compile it on linux.Teplitz
Yes, it already works on Windows. We use the matlab-generated dll in a .NET Framework 4.5 application. We are cloudify-ing the application to run on linux containers so the matlab code needs to run there as well. The mlfHaveSomePi implementation is just proof-of-concept code that returns 3.1415 from the matlab function,it's purpose is to help me understand the problem. As @MarkusDresch pointed out, I can't use the managed library generated on Windows in the linux container because of binary format differences (ELF vs PE).Thetis
I was able to look at the signatures of methods in MWArray.dll that gave me some hints on how to call the libmclmcrr.so.9.5 library on Linux. Since .NET on Linux is not supported by MathWorks at this time, I'll probably write a driver in C++ and then call that from my C# code. Thanks!Thetis
P
0

I'm not a mathlab user, so I might be wrong, very wrong!


Getting Linux .dll equivalent

What you need, is the correct shared library/object for the run-time OS to be exported from mathlab.

  • Windows: .dll = Dynamic Link Library
  • Linux: .so = shared object [.net core butter and bread for Linux]

Instruction to get .so exported lib from mathlab Compile your MATLAB files into a shared library (on UNIX)

mcc -t -L C -W MyMath-T link:lib haveSomePi.m libmmfile.mlib

Resulting MyMath.so, MyMath.exports, MyMath.h and MyMath.mlib, more details here


Binding Assembly

Make sure you have MyMath.so file next to MyMath.dll file, (bin, app data or where is needed)

Custom "NativeLibraryLoader" can be used to load different shared lib files based on OS, written by a GIT user because .net core din't had any (link). I would say is a bit over-complicated, but is your choice.

[DllImport] can be used instead!

  1. DllImport without extension, supported on Windows and Linux and MAC will import the appropriate library for the target platform.
 [DllImport("MyMath")] 
  1. Use <dllmap/> to map an import library name to the target platform library name. For MyMath.dll the corresponding Linux .so should be MyMath.so (more here)
 [DllImport("MyMath.dll")] 

Config map in csproj

<configuration>
  <dllmap dll="MyMath.dll" target="MyMath.so" />
</configuration>
Primero answered 4/2, 2019 at 10:59 Comment(2)
Cool. I didn't know about the "dllmap" element in the csproj, that's a lot easier than what I was doing for when the name munging isn't enough. Part of my research gave me hints to making the calls to the shared lib. For example, when MyMath.h has a double-pointer in the functions signature, mxArray** hal, I need to use an array of pointers, IntPtr[] hal, in the corresponding method signature. The problem isn't so much "how do I load an external library" but "how do I get my results from the pointers?"Thetis
Well, usually we jump head first, we'll figure out after what;s wrong :DPrimero
S
0

I think the main concern here is that you are doing

C Shared Library

Which is NOT C#...

Instead you should be doing

.NET Assembly

https://in.mathworks.com/help/compiler_sdk/gs/create-a-dotnet-application-with-matlab-code.html

It's important to note that .NET Core is not supported either, and you will have to change your project to a "classic" .NET Framework (If I recall correctly, at least 4.x)

Shipentine answered 13/5, 2019 at 5:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.