Minimal effort method for integrating C++ functions into Mathematica

Update: I posted a tutorial series on LibraryLink at Wolfram Community.

Update: LibraryLink example code is also available on this GitHub repository.


Here is my pitch to use LibraryLink, which is a really nice new technology in version 8. I am not going to pretend this is easy by any stretch of the imagination, because it involves a decent amount of knowledge of both Mathematica and C compilers. In this particular case I am using Visual Studio C++ Express plus the Microsoft Windows SDK 7.1. For the record, I had quite a bit of help from Joel Klein with this answer.

LibraryLink is set up to find most compilers on your system, but in my case I had to restart after installing the above tools (although looking back I think restarting my open frontend might have done the trick as well).

There are several examples of how to use LibraryLink in the documentation, but this example I wrote from scratch. All LibraryLink C code is compiled with the CreateLibrary function (which is located in the CCompilerDriver package.

Mathematica side

I'll skip the source for now, and focus on the Mathematica commands. First we loads the package to run the library link utility functions:

Needs["CCompilerDriver`"]

Next, we load the source file and create a library (.dll) from it:

myLibrary = 
  CreateLibrary[{"c:\\users\\arnoudb\\myLibrary.c"}, "myLibrary", "Debug" -> False];

Next, we load the one function defined in this library:

myFunction = LibraryFunctionLoad[myLibrary, "myFunction", {{Real, 2}}, {Real, 2}];

Next we use this function:

myFunction[{{1, 2, 3, 4}, {5, 6, 7, 8}}]

which returns the square of every matrix entry: {{1., 4., 9., 16.}, {25., 36., 49., 64.}}.

Finally, we unload the library (needed if we make changes to the source file and reload everything above):

LibraryUnload[myLibrary];

C side

There is a lot of boiler plate magic, to make things 'work'. These first four line need to always be included:

#include "WolframLibrary.h"
DLLEXPORT mint WolframLibrary_getVersion(){return WolframLibraryVersion;}
DLLEXPORT int WolframLibrary_initialize( WolframLibraryData libData) {return 0;}
DLLEXPORT void WolframLibrary_uninitialize( WolframLibraryData libData) {}

This is the actual function that you write. The function header is always the same, you get the actual function arguments from the MArgument_* api functions:

DLLEXPORT int myFunction(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res){

 int err; // error code

 MTensor m1; // input tensor
 MTensor m2; // output tensor

 mint const* dims; // dimensions of the tensor

 mreal *data1; // actual data of the input tensor
 mreal *data2; // data for the output tensor

 mint i; // bean counters
 mint j;

This gets the input tensor and dimensions and sets up the output tensor and actual data:

 m1 = MArgument_getMTensor(Args[0]);
 dims = libData->MTensor_getDimensions(m1);
 err = libData->MTensor_new(MType_Real, 2, dims,&m2);
 data1 = libData->MTensor_getRealData(m1);
 data2 = libData->MTensor_getRealData(m2);

The actual interesting stuff, this squares each element:

 for(i = 0; i < dims[0]; i++) {
  for(j = 0; j < dims[1]; j++) {
   data2[i*dims[1]+j] = data1[i*dims[1]+j]*data1[i*dims[1]+j];
  }
 }

This set the return value (and yes, you don't want to return the 'err' value here):

 MArgument_setMTensor(Res, m2);
 return LIBRARY_NO_ERROR;
}

On Windows, C/C++ functions that have been compiled into DLLs can be accessed reasonably easily using NETLink. Let's say we have the following C++ DLL definition:

#include "stdafx.h"

BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
    return TRUE;
}

extern "C" __declspec(dllexport)
void helloMma(double a, double b, int n, double m[]) {
    for (int i = 0; i < n ; ++i) {
        m[i] = a * i + b;
    }
}

We can import this function into Mathematica as follows:

Needs["NETLink`"]

$dllPath = "C:\\some\\path\\to\\hellomma.dll";

helloMma = DefineDLLFunction[
  "helloMma", $dllPath, "void", {"double", "double", "int", "double[]"}
]

Alas the calling sequence for this function is complicated slightly by the fact that it returns its result by destructively overwriting a statically allocated array of doubles (not an uncommon occurrence). To do this from Mathematica, we must pre-allocate the result vector using NETNew:

In[23]:= NETBlock@Module[{n, result}
         , n = 10
         ; result = NETNew["System.Double[]", n]
         ; helloMma[3, 5, n, result]
         ; NETObjectToExpression[result]
         ]
Out[23]= {5., 8., 11., 14., 17., 20., 23., 26., 29., 32.}

Note that all the usual Bad Things would happen if the pre-allocated buffer were overrun. NETBlock is used to ensure that the storage allocated for the buffer is released when we are done with it.

I will point out a couple of "gotchas". Make sure that the DLL is compiled as 32-bit or 64-bit to match the version of Mathematica that you are running. Also, note that the exported DLL function in the example is declared as extern "C". This prevents the C++ compiler from "mangling" the name and makes it easier to reference in the DefineDLLFunction declaration (in this case the Visual Studio C++ mangled name was ?helloMma@@YAXNNHQEAN@Z).


Presuming that your c++ code is already written, then I don't know how the code generation feature would be helpful. That said, in order of simplicity, I would have Get, ReadList, Import, and both LibraryLink and MathLink.


Get and ReadList are by far the simplest. Provided that your c++ program outputs to stdout (std::cout), then it is simply

val = (<<"!command")

or,

ReadList["!command", Number (*or some other specifier*)]

If you need to control your external program more directly, or pass additional data to it (like run your function multiple times), then this method is more difficult and may require you to open pipes to communicate through (1, 2).


Import would require you to conform to some data format, which while very doable, is not as simple as just putting numbers onto stdout.


I have never used LibraryLink, but a quick perusal of the docs implies that it is a simplification of the MathLink interface. More specifically, it is easier to create a function that can communicate with Mathematica, but the intricacies of sending data back and forth remain. To return a List, though, is not to bad, and may well be worth it. The catch, of course, is that you need to provide a c interface to your function, which differs from the MathLink form, but is still necessary. So, I'm not sure there is an advantage here for one or the other.