Search code examples
matlabmatlab-deploymentmatlab-compiler

How to compile Matlab class into C lib?


The origin of this question is from here How to use "global static" variable in matlab function called in c.

I'm trying to encapsulate the "global variable" into an object. However I don't know how to export the matlab class to c++ using MATLAB Compiler (mcc)

To do this I just tried the standard command

Matlab Command

mcc -W cpplib:Vowel4 -T link:lib Vowel4.m

Matlab Script

classdef Vowel4

  properties
    x
    y
  end

  methods
    Vowel4
    A
    B
  end

end

The generated lib is actually stand-alone functions rather than c++ class.

How can I compile classes in Matlab into c++ classes?

I've been searching for an answer but didn't find one.

Obviously the matlab command is not suitable for this scenario. However I cannot find any information on building Matlab classes into c++ classes.

========================== Edit ========================

The actual cpp code is as follows: @Alan

mclInitializeApplication(NULL, 0);
loadDataInitialize();
soundByCoefInitialize();
loadData(); 

mwArray F(4, 1, mxDOUBLE_CLASS);
float test[4];

for ( ;; ){
    const Frame frame = controller.frame();
    const FingerList fingers = frame.fingers();
    if ( !fingers.empty() ){
        for ( int i = 0; i < 4; i ++ ){
            double v = fingers.count() > i ? (fingers[i].tipPosition().y / 50) - 2 : 0;
            F(i+1,1) = v;
            test[i] = v;
            cout << v << ' ';
        }
        cout << endl;
        soundByCoef(F);
    }
}

Here the matlabA() corresponds to the loadData(), which loads the data, and soundByCoef(F) corresponds to the matlabB(), which do the job in the main loop.


Solution

  • As noted by Alan, I was only suggesting using handle class as a container for your global variables (with the benefit that such an object would be passed by reference). The created object is not intended to be directly manipulated by your C++ code (it will be stored in the generic mxArray/mwArray C/C++ struct).

    As far as I know, you cannot directly compile classdef-style MATLAB classes into proper C++ classes when building shared libraries using the MATLAB Compiler. It only supports building regular functions. You could create functional interfaces to MATLAB class member methods, but that's a different story...

    Perhaps a complete example would help illustrate the idea I had in mind. First lets define the code on the MATLAB side:

    GlobalData.m

    This is the handle class used to store the global vars.

    classdef GlobalData < handle
        %GLOBALDATA  Handle class to encapsulate all global state data.
        %
        % Note that we are not taking advantage of any object-oriented programming
        % concept in this code. This class acts only as a container for publicly
        % accessible properties for the otherwise global variables.
        %
        % To manipulate these globals from C++, you should create the class API
        % as normal MATLAB functions to be compiled and exposed as regular C
        % functions by the shared library.
        % For example: create(), get(), set(), ...
        %
        % The reason we use a handle-class instead of regular variables/structs
        % is that handle-class objects get passed by reference.
        %
    
        properties
            val
        end
    end
    

    create_globals.m

    A wrapper function that acts as a constructor to the above class

    function globals = create_globals()
        %CREATE_GLOBALS  Instantiate and return global state
    
        globals = GlobalData();
        globals.val = 2;
    end
    

    fcn_add.m, fcn_times.m

    MATLAB functions to be exposed as C++ functions

    function out = fcn_add(globals, in)
        % receives array, and return "input+val" (where val is global)
    
        out = in + globals.val;
    end
    
    function out = fcn_times(globals, in)
        % receives array, and return "input*val" (where val is global)
    
        out = in .* globals.val;
    end
    

    With the above files stored in current directory, lets build the C++ shared library using the MATLAB Compiler:

    >> mkdir out
    >> mcc -W cpplib:libfoo -T link:lib -N -v -d ./out create_globals.m fcn_add.m fcn_times.m
    

    You should expect the following generated files among others (I'm on a Windows machine):

    ./out/libfoo.h
    ./out/libfoo.dll
    ./out/libfoo.lib
    

    Next, we could create a sample C++ program to test the library:

    main.cpp

    // Sample program that calls a C++ shared library created using
    // the MATLAB Compiler.
    
    #include <iostream>
    using namespace std;
    
    // include library header generated by MATLAB Compiler
    #include "libfoo.h"
    
    int run_main(int argc, char **argv)
    {
        // initialize MCR
        if (!mclInitializeApplication(NULL,0)) {
            cerr << "Failed to init MCR" << endl;
            return -1;
        }
    
        // initialize our library
        if( !libfooInitialize() ) {
            cerr << "Failed to init library" << endl;
            return -1;
        }
    
        try {
            // create global variables
            mwArray globals;
            create_globals(1, globals);
    
            // create input array
            double data[] = {1,2,3,4,5,6,7,8,9};
            mwArray in(3, 3, mxDOUBLE_CLASS, mxREAL);
            in.SetData(data, 9);
    
            // create output array, and call library functions
            mwArray out;
            fcn_add(1, out, globals, in);
            cout << "Added matrix:\n" << out << endl;
            fcn_times(1, out, globals, in);
            cout << "Multiplied matrix:\n" << out << endl;
        } catch (const mwException& e) {
            cerr << e.what() << endl;
            return -1;
        } catch (...) {
            cerr << "Unexpected error thrown" << endl;
            return -1;
        }
    
        // destruct our library
        libfooTerminate();
    
        // shutdown MCR
        mclTerminateApplication();
    
        return 0;
    }
    
    int main()
    {
        mclmcrInitialize();
        return mclRunMain((mclMainFcnType)run_main, 0, NULL);
    }
    

    Lets build the standalone program:

    >> mbuild -I./out main.cpp ./out/libfoo.lib -outdir ./out
    

    And finally run the executable:

    >> cd out
    >> !main
    Added matrix: 
         3     6     9 
         4     7    10 
         5     8    11 
    Multiplied matrix: 
         2     8    14 
         4    10    16 
         6    12    18 
    

    HTH