Interaction with Mathematica

Wolfram LibraryLink allows dynamic libraries to be directly loaded into the Mathematica kernel so that functions in the libraries can be immediately called from Mathematica. You can exchange not only C-like data types such as integers, reals, packed arrays, and strings, but also arbitrary Mathematica expressions. In addition, there are useful functions such as sending errors and calling back to Mathematica.

This section describes the functions that Mathematica provides for working with Wolfram Libraries.

LibraryFunctionLoadload a function from a library
LibraryFunctionrepresentation of a handle to a function loaded from a library
LibraryFunctionUnloadunload a function that was previously loaded from a library
LibraryUnloadunload all functions previously loaded from a library
LibraryFunctionInformationreturns information about a LibraryFunction
$LibraryPaththe path used to find libraries
FindLibraryfind a library
LibraryLoadload a library required by other libraries

Mathematica functions for working with libraries.

LibraryFunctionLoad loads a function from a library and returns a LibraryFunction.

In[1]:=
Click for copyable input
Out[1]=

Here the LibraryFunction is called with an integer argument.

In[2]:=
Click for copyable input
Out[2]=

LibraryFunctionInformation returns information about the LibraryFunction, such as the library from which it was loaded, as well as the argument and return types.

In[3]:=
Click for copyable input
Out[3]=

Library Specification

The first argument to LibraryFunctionLoad is the library to load. This can be given as an absolute file name such as C:\Libraries\myLibrary.dll. However, it is often more convenient to give a relative specification to the library, finding it from a path. Another problem is that different platforms use different file name extensions for libraries. The conventions are summarized in the following table.

Windowsdll
Unix and Linuxso
Mac OS Xdylib

Extensions for dynamic libraries on different systems.

Mathematica provides a solution to this with FindLibrary and $LibraryPath. FindLibrary can take a platform-independent specification of a library, look for it on $LibraryPath, and, if it finds the library, return the actual file for your system.

The following searches on $LibraryPath and finds the library suitable for your platform; in this example it is Windows.

In[4]:=
Click for copyable input
Out[4]=

More information on how $LibraryPath is set up is found in "Locating Libraries".

Function Name

The second argument to LibraryFunctionLoad gives the name of the function to load. This function should be exported from the library, as described in "Library Structure". Note that if you compile the library as C++ you should probably export it with a C naming convention; this is also described in "Library Structure".

Type Specification

The third and fourth arguments to LibraryFunctionLoad specify the types of the arguments and the return type.

"Boolean"mboolBoolean
Integermintmachine integer
Realdoublemachine double
Complexmcomplexmachine complex double
{base,rank}MTensortensor of specified base type and rank
{base,rank,memory}MTensortensor with specified memory management
"UTF8String"char *UTF8 string
LinkObjectMLINKarguments and result written to MathLink
"Void" no result (return only)

Argument and return type specification.

The types that specify tensors are designed to map directly to Mathematica packed arrays and also to use of tensors in the Mathematica compiler. This gives the system great efficiency and allows libraries access to many tensor operations. Tensors can specify the type of each element and the rank explicitly, or they can be left unspecified. Unspecified types and rank give a lot of flexibility for applications that work with tensors. Note that tensors are only supported for Integer, Real, and Complex.

{Integer, 1}tensor of specified base type and rank
{Real, _}tensor with specified base type and arbitrary rank
{_,_}tensor with arbitrary base type and arbitrary rank

Tensor type specification.

When a tensor is passed as an argument you can also specify how its memory is handled. This is discussed in detail in the next section.

In the code of your library function you collect the data from each type from the argument array. Macros for MArgument have been provided to make this collection easy and straightforward. Sample code is shown below.

  mint I0 = MArgument_getInteger(Args[0]);
double R0 = MArgument_getReal(Args[1]);
mcomplex C0 = MArgument_getComplex(Args[2]);
MTensor T0 = MArgument_getMTensor(Args[3]);

When you return from the library function, you must assign to the result. A sample that stores a double is shown below.

  MArgument_setReal(Res, R1);

If you specify tensor input but with arbitrary type and rank, you can find the actual type and rank with the callback functions, as in the following.

  type = libData->MTensor_getType( T0);
rank = libData->MTensor_getRank( T0);

MTensor_getType returns an integral value that represents the type of the result.

MType_Integeran MTensor that contains machine integers
MType_Realan MTensor that contains machine doubles
MType_Complexan MTensor that contains complex numbers (real and imaginary part being machine doubles)

Results for MTensor_getType.

If the library function takes no arguments then you simply pass an empty list for the input specification.

In[7]:=
Click for copyable input
Out[7]=
In[8]:=
Click for copyable input
Out[8]=

If the library function does not return a result, you can use a return specification of .

In[9]:=
Click for copyable input
Out[9]=
In[10]:=
Click for copyable input

Memory Management of MTensors

Types such as mint, double, and mcomplex are passed to and returned from libraries by value, as is common for calling C functions. The usage in the library is really independent of that in Mathematica.

By contrast, an MTensor is a pointer to a data structure, and thus they are passed by reference. A consequence is that you have to think about how its memory is managed. Mathematica chooses a default technique that is safe and simple, but if you want to pass in large amounts of data or save it for future usage then you need to think about its management.

MTensor Input Arguments

When you pass an MTensor to a library function you have a number of options that determine how this is done.

{Integer, 1}pass in a copy of the MTensor and automatically clean
{Integer, 1, Automatic}pass in a copy of the MTensor and automatically clean
{Integer, 1, "Constant"}pass in a reference to the MTensor that should not be modified
{Integer, 1, "Manual"}pass in a copy of the MTensor and do not automatically clean
{Integer, 1, "Shared"}pass in a reference to the MTensor shared between a library and Mathematica

Memory management possibilities for MTensor arguments to library functions.

Automatic Passing

If you select automatic passing this means that the MTensor is copied before the function is called and it will be cleaned when the function returns. This would be suitable for a function such as the following.

DLLEXPORT int demo_TI_R(WolframLibraryData libData,
        mint Argc, MArgument *Args, MArgument Res) {
    MTensor T0;
    mint I0;
    double R0;
    T0 = MArgument_getMTensor(Args[0]);
    I0 = MArgument_getInteger(Args[1]);
    R0 = libData->MTensorVector_getReal(T0, I0);
    MArgument_setReal(Res, R0);
    return LIBRARY_NO_ERROR;
}

In this function there is no need to free the MTensor. However, you could not save a reference to the MTensor and use it once the function has finished.

An MTensor passed with automatic passing is owned for both read and write access by the library function only as long as the function call is active.

Constant Passing

If you select constant passing, this means that a reference to the MTensor is passed in and it is assumed that your function will not modify the MTensor in any way. This effectively gives you very fast read-only access to the MTensor data. If your code breaks this assumption and does modify the data, a grave error could result in your Mathematica session.

An MTensor passed with constant passing is owned by the library function for read access only as long as the function call is active.

Manual Passing

If you select manual passing this means that the MTensor is copied before the function is called and it is not cleaned when the function returns. This would be suitable for a function such as the following.

DLLEXPORT int demo1_TI_R(WolframLibraryData libData,
            mint Argc, MArgument *Args, MArgument Res) {
    MTensor T0;
    mint I0;
    double R0;
    T0 = MArgument_getMTensor(Args[0]);
    I0 = MArgument_getInteger(Args[1]);
    R0 = funStruct->MTensorVector_getReal( T0, I0);
    libData->MTensor_free(T0);
    MArgument_setReal(Res, R0);
    return LIBRARY_NO_ERROR;
}

Note how the function frees the MTensor. If it were not freed, the memory would be lost. However, instead of freeing the tensor, you could save the tensor and use it in some other part of the library. Finally, if you finish with the tensor you should call MTensor_free. An alternative would be to return it from a library function to Mathematica in which ownership would pass back to Mathematica.

An MTensor passed with manual passing is completely owned by the library; this continues until the MTensor is freed or passed back to Mathematica.

Shared Passing

If you select shared passing this means that the MTensor is not copied before the function is called, it is just passed directly to the library function. This would be suitable for a function such as the following.

DLLEXPORT int demo2_TI_R(WolframLibraryData libData,
            mint Argc, MArgument *Args, MArgument Res) {
    MTensor T0;
    mint I0;
    double R0;
    T0 = MArgument_getMTensor(Args[0]);
    I0 = MArgument_getInteger(Args[1]);
    R0 = funStruct->MTensorVector_getReal( T0, I0);
    libData->MTensor_disown( T0);
    MArgument_setReal(Res, R0);
    return LIBRARY_NO_ERROR;
}

When you use shared pass in arguments, the MTensor is shared between Mathematica and your library. Mathematica keeps the MTensor in a table to make sure that its memory does not get collected. When your library no longer wants to use the MTensor, you should call MTensor_disown.

An MTensor passed with shared passing is shared between the library and Mathematica. It will be kept alive until the library and Mathematica have finished all usages.

This loads a sample function using to pass in the arguments.

In[1]:=
Click for copyable input
Out[1]=

This creates a packed array suitable for using as an argument for the function.

In[2]:=
Click for copyable input
Out[3]=

Here you can call the function passing in the array.

In[4]:=
Click for copyable input
Out[4]=

However, if you call the function with an argument that is not a packed array, the call will work, but you will get a warning message. This is because Mathematica had to convert the input into a packed array, thereby copying the data and losing one of the advantages of using shared passing.

In[5]:=
Click for copyable input
Out[6]=

MTensor Return

When you return an MTensor from a library function you also control how its memory is managed.

{Integer, 1}return a reference to the MTensor for Mathematica
{Integer, 1, Automatic}return a reference to the MTensor for Mathematica
{Integer, 1, "Shared"}return a reference to the MTensor shared between a library and Mathematica

Memory management possibilities for MTensor results from library functions.

Automatic Return

If you select automatic return this means that the MTensor goes directly back from the library to Mathematica, which will use it as the result of the library function.

DLLEXPORT int demo_I_T(WolframLibraryData libData, 
            mint Argc, MArgument *Args, MArgument Res) {
    MTensor T0;
    mint i, I0, dims[1];
    int err = LIBRARY_NO_ERROR;

    I0 = MArgument_getInteger(Args[0]);
    dims[0] = I0;
    
    err = libData->MTensor_new(MType_Integer, 1, dims, &T0);
    for ( i = 1; i <= I0 && !err; i++) {
        err = libData->MTensor_setInteger( T0, &i, i*2);
    }
    MArgument_setMTensor(Res, T0);
    return err;
}

If the MTensor is owned by the library, i.e. it was created in the library or passed in with manual passing, then once it has been returned to Mathematica it is no longer owned by the library, which should not make any usage of it whatsoever. This is shown in the function above.

If the MTensor is shared between the library and Mathematica then automatic return does not change anything in the ownership of the MTensor. However, it is rather strange to return a shared MTensor from a library since Mathematica already has a reference to it.

Shared Return

If you select shared return this means that the MTensor will be shared between the library and Mathematica. Technically this is implemented by adding it to the sharing table when the function returns. This makes sure the MTensor does not get collected. When your library no longer wants to use the MTensor, you should call MTensor_disown (or MTensor_disownAll).

Note that if you call MTensor_disown (or MTensor_disownAll) before the MTensor has been added to the sharing table it will have no effect and a warning message will be issued.

MTensor Memory Management Summary

One way to understand the three different types of memory management for an MTensor is to consider how the MTensor is "owned" between the different components.

For automatic passing, the MTensor is owned by the library function only when that call to the library is active. The function can return the MTensor whether it has been modified or not, but whatever happens, the MTensor cannot be used after the function has returned.

For manual passing, the MTensor is owned by the library after the function has been called. The MTensor can be used at any time after the function, for example, in another function. The MTensor will continue to be owned by the library until either it is returned by a library function or it is passed to a call to MTensor_free. If you want to return an MTensor that was passed in with manual passing but keep ownership in the library, you will have to copy it with a call to MTensor_clone or return it from a function that uses shared return.

For shared passing and return, ownership of the MTensor is shared between Mathematica and the library. If the Mathematica expression that holds the packed array for the MTensor can no longer be reached, Mathematica will no longer have ownership. The library will also keep ownership until you have called MTensor_disown on the MTensor. Note that you have to call MTensor_disown on an MTensor as many times as you have passed it into and returned from a function. For example, if you pass the same packed array into a library three times, then you need to call MTensor_disown three times. The function MTensor_disownAll can be useful to remove all references, and the function MTensor_shareCount gives the actual number of times the MTensor is shared.

A final thing to remember is that if any errors arise these might transfer control away from the parts of your library function that free memory. In this case you might want to insert your own error handler; this is discussed in the section on errors.

String Arguments

String arguments are passed in with characters encoded using UTF8. When a string is passed as an argument, memory management for the string is left completely up to the program, similar to the manual passing for an MTensor.

DLLEXPORT int countSubstring(WolframLibraryData libData,
            mint Argc, MArgument *Args, MArgument Res)
{
    char *instring = MArgument_getUTF8String(Args[0]);
    char *substring = MArgument_getUTF8String(Args[1]);
    mint i, n = strlen(instring);
    mint slen = strlen(substring);
    mint c = 0;
    if (n > slen) {
        n -= slen;
        for (i = 0; i <= n; i++) {
            if (!strncmp(instring + i, substring, slen)) {
                c++;
            }
        }
    }
    MArgument_setInteger(Res, c);
    libData->UTF8String_disown(instring);
    libData->UTF8String_disown(substring);
    return LIBRARY_NO_ERROR;
}

Note how the memory for both string arguments is released using UTF8String_disown. If this is not done and you do not otherwise keep a reference to the string argument in your program, the memory will simply be lost. When a string is returned as a result, Mathematica accesses the memory to convert it to its own internal string format, but does not attempt to free the memory. Thus, if your program allocates a string for a result, it also needs to free that memory, but in a separate function from the one setting the string result, since Mathematica needs to access the string memory after the library function has returned.

LinkObject Arguments and Result

If you want to send arguments or get results from the library function that are not covered by the MTensor basic numerical types, you can use a LinkObject for arguments and the result. This will let you send the structure of any Mathematica expression to your library.

For LinkObject arguments and the result, the library is called in a different way than for basic numerical types. When the function is called, Mathematica writes a list with all the arguments onto a MathLink connection; this is done with LinkWrite, the way Mathematica writes expressions over MathLink. Then it calls the library function. The library function must read the arguments from the link, do its work, and then write its result back onto the link. Mathematica then reads the result from the link with LinkRead, the way that Mathematica reads expressions from MathLink.

An example of a function that works for LinkObject arguments and result is shown below.

DLLEXPORT mint reverseString( WolframLibraryData libData, MLINK mlp)
{
    mint res = 0;
    int i1, i2, sum;
    int len;
    const char *inStr = NULL;
    char* outStr = NULL;
    
    if ( !MLCheckFunction( mlp, "List", &len))
        goto retPt;
    if ( len != 1)
        goto retPt;

    if(! MLGetString(mlp, &inStr))
        goto retPt;

    if ( ! MLNewPacket(mlp) )
        goto retPt;

    outStr = reverseStringImpl(inStr);
    res = MLPutString( mlp,outStr);
retPt:
    if ( inStr != NULL)
        MLReleaseString(mlp, inStr);
    if ( outStr != NULL)
        free(inStr);
    return res;
}

This loads a sample function that uses LinkObject arguments and result.

In[7]:=
Click for copyable input
Out[7]=

This calls the function.

In[8]:=
Click for copyable input
Out[8]=

To use MathLink for communicating with Mathematica, the "mathlink.h" header must be included before the "WolframLibrary.h" header.

Locating Libraries

The first argument to LibraryFunctionLoad is the library to load. This can be given as an absolute file name such as C:\Libraries\myLibrary.dll. However, it is more convenient to give a relative specification to the library, finding it from a path. Also, since different platforms use different extensions for dynamic libraries, it can also be a problem to give the extension. The conventions for extensions for dynamic libraries are summarized in the following.

Windowsdll
Unix and Linuxso
Mac OS Xdylib

Extensions for libraries on different systems.

Functions in Mathematica that work with dynamic libraries automatically solve this problem. If the input name does not have a file extension, then one suitable for your platform is added. This lets you work with libraries in ways that are independent of the machine on which you work. In addition, Mathematica provides a path, $LibraryPath, to use to find libraries.

A sample setting for $LibraryPath is shown below. Note that it includes a number of Mathematica applications that contain libraries.

In[1]:=
Click for copyable input
Out[1]=

FindLibrary is the function that finds libraries. It is called by other commands such as LibraryFunctionLoad. FindLibrary first fixes the extension of the library, then looks for the library as an absolute name, and finally looks for the library on $LibraryPath. It returns the file if it is found.

The following searches on $LibraryPath and finds the library suitable for your platform; in this example it is Windows.

In[9]:=
Click for copyable input
Out[9]=

You can also use a name with an extension, but note that this will only work on a platform for which the extension is appropriate.

In[10]:=
Click for copyable input
Out[10]=

You can add elements to $LibraryPath. However, a number of folders are automatically added; this includes any LibraryResources folder found in a Mathematica application in $UserBaseDirectory/Applications or $BaseDirectory/Applications. This is similar to the way that J/Link can load Java classes, and DatabaseLink can load database resources. It gives a convenient way to bundle libraries with your Mathematica work.

Installing Your Own Libraries

If you want to add dynamic libraries to use in your Mathematica session you have a number of options. These are summarized here.

Absolute Pathname

You can assign an absolute pathname to a function such as LibraryFunctionLoad. This is easy to set up, but will cause problems if you move your work to a different computer.

Setting $LibraryPath

You can add the location of your libraries to $LibraryPath. This gives more abstraction over the use of an absolute pathname, since you can set the location once in a variable and use it many times.

In addition, you can use Block to temporarily change the setting of $LibraryPath. An example is shown below.

In[9]:=
Click for copyable input
$BaseDirectory and $UserBaseDirectory

$LibraryPath always includes two locations, $UserBaseDirectory/SystemFiles/LibraryResources/$SystemID and $BaseDirectory/SystemFiles/LibraryResources/$SystemID. If you place your library here it will be found by library loading functions.

This shows the location in $BaseDirectory.

In[3]:=
Click for copyable input
Out[3]=
Applications

If you deliver your code as a Mathematica application you can also include libraries that will be placed on $LibraryPath. You should include a LibraryResources directory with a folder that matches $SystemID. A sample application is shown below.

MyApplication
MyApplication.m
Kernel
init.m
FrontEnd
Documentation
English
LibraryResources
Windows
libraries for use on Windows
Windows-x86-64
libraries for use on 64 bit Windows
Linux
libraries for use on Linux
Linux-x86-64
libraries for use on 64 bit Linux
MacOSX-x86
libraries for use on MacOSX
MacOSX-x86-64
libraries for use on 64 bit MacOSX

Library Dependencies

If your library depends on other libraries you will need to make sure that the dependent libraries are available. You could do this by changing the environment in which Mathematica runs to install these extra libraries in some system location, or by changing a path environment variable such as LD_LIBRARY_PATH (for Linux) or PATH (for Windows).

An alternative is to use LibraryLoad to load the dependent libraries before loading your own library. LibraryLoad does not return a function (unlike LibraryFunctionLoad), it merely exists to load dependent libraries.

Under Mac OS X, dynamic libraries (which have a file extension of dylib) have a more complicated mechanism where they can be set up to search in particular places for dependent libraries. You should consult the description of commands such as otool and install_name_tool.

If you have trouble loading a library, you can use $LibraryError to find out more about why it did not load. In some cases this returns information about which dependent libraries cannot be loaded.

Library Version Information

You can get information about the version of a library with the LibraryLink Package. This supplies some extra tools for working with shared libraries.

To use the package you have to load it.

In[1]:=
Click for copyable input

This finds a library.

In[2]:=
Click for copyable input
Out[2]=

Here, LibraryVersionInformation returns a list of rules that shows information about the library.

In[3]:=
Click for copyable input
Out[3]=

You can also get the version information as a string with LibraryVersionString, as shown in the following.

In[4]:=
Click for copyable input
Out[4]=

Problems Loading a Library

If you have problems loading a library, you might want to use $LibraryError to find out more about why it did not load. This is found in the LibraryLink` context, but you do not have to load the package to use it.

Here, a library used for calendar calculations is loaded.

In[1]:=
Click for copyable input
Out[1]=

The library has dependencies on other libraries. Normally, Mathematica will load the other libraries first. However, if you just try to load the calendar library directly (and you have not already used a calendar function) this load instruction will fail, as in the following.

You can use $LibraryError to find out more about the error, as shown below.

In[3]:=
Click for copyable input
Out[3]=
Click for copyable input

Windows does not give the names of dependent libraries that cannot be found. On other platforms this information is available.

New to Mathematica? Find your learning path »
Have a question? Ask support »