Generating C Code from MATLAB for Use with Java and .NET Applications

By Christophe Pouillot, MathWorks

You can maximize usage of an algorithm developed, tested, and validated in MATLAB® by sharing it with others who may not have MATLAB installed. To avoid the development and testing costs associated with re-coding the algorithm in another language, two approaches are available: use MATLAB Compiler™ SDK or use MATLAB Coder™.

MATLAB Compiler SDK encrypts your algorithm and packages it into C/C++ shared libraries, Microsoft® .NET assemblies, Python® packages, and Java® classes. Applications built with these components run against the MATLAB Runtime, which provides access to the MATLAB language, graphics, and toolboxes without the MATLAB interface. The MATLAB Runtime can be installed on any target platform capable of running MATLAB, such as desktop or server platforms running Windows, MacOS, or Linux.

If installing the MATLAB Runtime on your target platform is not possible, consider generating C or C++ code from the numeric computational portion of your MATLAB algorithms using MATLAB Coder. The generated code can then be used as a component of a larger system. This approach works well for smartphone platforms, such as Android and iOS.

This article presents a workflow for using MATLAB Coder to deploy MATLAB applications in a C/C++, .NET, or Java environment without installing the MATLAB Runtime. The workflow is illustrated using code for a Kalman filter.

The code used in this example is available for download.

Workflow for C/C++, .NET, and Java Target Platforms

The starting point for deploying to C/C++, .NET, or Java target platforms is to generate C code from your MATLAB code using MATLAB Coder. The next step is target-specific, as follows:

  • For a C/C++ platform, you use the generated C code directly.
  • For a .NET platform, you use the C code directly via Platform Invocation Services (P/Invoke), a technology that enables managed code to call native code.
  • For a Java platform, you write C wrapping code to enable the generated C code to be used with Java Native Interface (JNI)1

The prototype of the Kalman filter function in MATLAB is:

 function y = kalmanfilter(z)%% MATLAB Code 

Deploying to.NET

To prepare the application to run on a .NET platform, follow these five steps (Figure 1):

Figure 1. Steps to deploy MATLAB to a .NET platform.
  1. Run MATLAB Coder to generate C code and a DLL from your MATLAB code.

You can either create a MATLAB Coder project or run the command-line function codegen. Both methods let you specify the output directory and the name of the generated DLL—a good practice because it avoids cluttering the MATLAB current folder with generated files.

For the Kalman filter, the MATLAB command to generate the C code is:

codegen –o MATLAB_CODER_DLL –d ..\autogen_matlabcoder 
kalmanfilter.m -args {zeros(2,1)} 
  1. Open the header file *.h generated by MATLAB Coder to review the C function interfaces generated from your MATLAB functions.

In our example, the MATLAB Kalman filter will be translated into a C function whose prototype is:

 extern void kalmanfilter(const double z[2], double y[2]); /* C code */ 

We generate the Kalman filter for double arguments because double is the MATLAB default type. (Note that MATLAB Coder lets you change the datatype for the generated code without changing your MATLAB code.)

  1. Review the C data type of the functions arguments and translate them into a .NET data type.

This step is important, as you will have to write a declaration of your function in .NET language. For more information, see Platform Invoke Data Types.

Table 1 shows the equivalent C and .NET types.

C Type .NET Type Description
void* System.IntPtr 32 bits on 32-bit Windows operating systems
64 bits on 64-bit Windows operating systems
unsigned char System.Byte 8 bits
short System.Int16 16 bits
unsigned short System.UInt16 16 bits
int System.Int32 32 bits
unsigned int System.UInt32 32 bits
long System.Int32 32 bits
unsigned long System.UInt32 32 bits
char System.Char Decorate with ANSI
wchar_t System.Char Decorate with Unicode
char* System.String or System.Text.StringBuilder Decorate with ANSI
donst char* System.String or System.Text.StringBuilder Decorate with ANSI
wchar_t* System.String or System.Text.StringBuilder Decorate with Unicode
Const wchar_t* System.String or System.Text.StringBuilder Decorate with Unicode
Float System.Single 32 bits
double System.Double 64 bits

Table 1. Equivalent C and .NET data types.

The table indicates that the “double” C type will be simply translated into a System.Double .NET type. This means that a C function prototype like this:

 void kalmanfilter(const double z[2], double y[2]); /* C code */ 

Can be translated into the following .NET C# function prototype:

 void kalmanfilter(Double[] a, Double[] b); /* C# code */ 

Be sure to match the .NET or Java types to the C types correctly. A mismatch will not throw an error at compile and run time, but the numeric values will be invalid.

  1. Write .NET code for declaring and calling your imported functions.

In our example, we write the following Visual Basic .NET code:

Visual Basic .NET code
Imports System.Runtime.InteropServices
Module Module1
    <DllImport("MATLAB_CODER_DLL.dll", 
CallingConvention:=CallingConvention.Cdecl)>
        Public Sub kalmanfilter(ByVal a() As Double, ByVal b() As Double)
    End Sub

    Sub Main()
        Dim ak As Double()
        ak = {1, 2}
        Dim bk As Double()
        bk = {0, 0}
        kalmanfilter(ak, bk)
    End Sub
End Module

In addition, we write the following code in C#.

/* C# code */
using System.Runtime.InteropServices; 
class Program
{
      [DllImport("MATLAB_CODER_DLL.dll",
               CallingConvention = CallingConvention.Cdecl)]
        public static extern void kalmanfilter(Double[] a, Double[] b);

      static void Main(string[] args)
      {
            Double[] ak = {1,2};
            Double[] bk = new Double[2];
            kalmanfilter(ak, bk);
}
}

Notice the similarity between the two types of code: Visual Basic .NET code presents a module with a “main” procedure in it, while C# has a class with a “main” method. Both code languages require the use of the InteropServices function, which contains the methods for P/Invoke technology.

Building the .NET code does not require the DLL file or the C header file. Instead, the build will rely on your own .NET declaration of your function in the “DllImport” statement. This means that if your .NET declaration is not compliant with the C declaration but is compliant with your .NET call, building the .NET code will not raise an error. The error will appear only at run time.

  1. Run the .NET code. Be sure to store the DLL file and your executable in the same folder.

Deploying to a Java Platform

To prepare the application to run on a .Java platform, follow these seven steps (Figure 2):

Figure 2. Steps to deploy MATLAB to a Java platform.
  1. Run MATLAB Coder to generate C code from your MATLAB code.

The MATLAB command to generate the C code for the Kalman filter is

codegen –c –o MATLAB_CODER_DLL –d ..\autogen_matlabcoder
 kalmanfilter.m -args {zeros(2,1)}

When deploying to JAVA we use the option “-c” , not the DLL, .to generate the C code,. We will need to write extra C code to get the final DLL for JAVA.

  1. Write Java code containing a Java declaration of your functions.

The Java declaration differs from the C declaration not only in its syntax and data type but also in its arguments. A C function takes array pointers as output arguments, while Java returns object arrays. You will have to translate your C prototype to Java prototype accordingly. Bear in mind, however, that a wrapper to your C functions, not the C native functions, will be directly called in your Java code.

For the Kalman filter, we write the following Java code and save it to a file named example.java.

public class example {
    /* loading the C DLL */
    static { System.loadLibrary("MATLAB_JNI"); } 
    /* functions prototypes */
    public static native double[] kalmanfilter(double[] a);
}

We could add the call to our function, but at this point in the workflow we only require the function declaration. We will add the call in step 5.

Notice that the resultant array is a return of the Java function, while it was an output argument of the C function.

  1. Generate a C header file from your saved Java file.

For our example we use the javah tool in the Java Development Kit. This tool creates C header file from a given Java class that includes native methods.

We run the following MATLAB command:

!javah example % MATLAB command

Like all the executable files in MATLAB system command, the file javah.exe must be known by the operating system on which MATLAB is run. On Windows, this means the environment variable PATH must contain the path to javah.exe.

The command above will generate a C header file that contains the following declaration of JNI C function:

JNIEXPORT jdoubleArray JNICALL 
 Java_example_kalmanfilter(JNIEnv *, jclass, jdoubleArray); 
  1. Write C implementation code for the JNI C declaration. This C wrapper code does the following:

    • Translates JAVA type data to C type data
    • Calls your C function
    • Translates C type data to JAVA type data

The wrapper C code for the Kalman filter looks like this:

JNIEXPORT jdoubleArray JNICALL Java_example_kalmanfilter
  (JNIEnv *env, jclass cls, jdoubleArray a) /* C code */
{
    jdouble temp[2];
    /* 1. copying JAVA array to C array */
    jdouble* ac = (*env)->GetDoubleArrayElements(env,a,0);
    /* creating new JAVA array */
    jdoubleArray result = (*env)->NewDoubleArray(env, 3); 
    if (result != NULL) {   
 
	  /* 2. calling the C function */
        kalmanfilter(ac, temp);

        /* 3. copying the C array to Java array */
        (*env)->SetDoubleArrayRegion(env, result, 0, 3, temp);
    }
    /* deleting temporary C array */
    (*env)->ReleaseDoubleArrayElements(env, a, ac, 0);
    return result;
}

Notice that the Java types themselves are translated into JNI types. Indeed, the double[]Java array type appears as a jdoubleArray, while the double Java type appears as a jdouble type.

Table 2 shows the equivalence between Java and Java JNI type (For more information, see JNI Types and Data Structures).

Java Type Native Type Description
boolean jboolean unsigned 8 bits
byte Jbyte signed 8 bits
char jchar unsigned 16 bits
short jshort signed 16 bits
Int jint signed 32 bits
Long jlong signed 64 bits
float jfloat 32 bits
double jdouble 64 bits
void void N/A

Table 2. Java and Java JNI data types.

  1. Build the JNI C DLL. The DLL includes:

    • The C source files created by the MATLAB  Coder in step 1
    • The C JNI header file created by the javah  tool in step 3
    • The wrapper C code for the JNI interface written in step 4
  1. Add function calls to your Java code and compile it.
/* JAVA code */
public class example {
    /* loading the C DLL */
    static { System.loadLibrary("MATLAB_JNI"); } 
    public static native void initialize();
    public static native double[] kalmanfilter(double[] a);
        
    public static void main(String[] args) {
        example myM = new example();
        myM.initialize();  // initializing the kalman filter
        double[] ak = {1,2};
        double[] bk = myM.kalmanfilter(ak); // calling the native method
    }   
}

Note the presence of an initialize function. This function was created by MATLAB Coder. It is required by the Kalman filter because the kalmanfilter MATLAB function uses a persistent variable. We thus need to declare and wrap the “initialize” function.

  1. Run the Java code. Makes sure that the DLL file is in the same folder as your Java executable.

Benefits of this Approach

We have outlined a workflow that lets you deploy a MATLAB algorithm onto any platform, even one not supported by MATLAB. The platform framework can be in C, C++, or Java.

The benefits of this workflow are numerous. Not only do you avoid the cost of rewriting the MATLAB code in another language and the cost of testing the translated code, you also save development time and get production-quality C code from MATLAB Coder.

1 The JNI technology is not the only way to call native C in JAVA code. You can also use a technology called JAVA Native Access (JNA). JNA requires the use of an additional package.

About the Author

Christophe Pouillot is a senior MathWorks consultant. His areas of specialty include automatic code generation, model verification and validation, and developing, deploying, and interfacing MATLAB and Simulink applications with other technical languages. Before joining MathWorks, Christophe designed and developed software applications in several industries, including energy, automotive, and aerospace. Christophe holds a B.S. and an M.S. in robotic engineering from Ecole Centrale de Nantes in France.

Published 2015 - 92946v00


View Articles for Related Capabilities