How to compile Matlab class into C lib?

后端 未结 2 2034
遥遥无期
遥遥无期 2020-12-19 14:10

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 variab

相关标签:
2条回答
  • 2020-12-19 14:59

    Following on from the thread in the previous post, the suggestion wasn't to wrap your functions in a class, but rather to use a class to pass about the global variable which compiling leaves you unable to use.

    classdef Foo < handle
      properties
        value
      end
    
      methods
        function obj = Foo(value)
          obj.value = value;
        end
      end
    end
    

    Note: the class Foo extends the handle class in order to make it pass by reference, rather than pass by value. See: the comparison between handle and value classes.

    function foo = matlabA()
      foo = new Foo(1);
    end
    
    function matlabB(foo)
      foo.value
    end
    

    As far as I know, the matlab compiler doesn't compile the code as such, but rather packages it with a copy of the MATLAB Component Runtime and writes some wrapper functions to handle invoking said runtime on the code from c/c++.

    I would recommend avoiding jumping back and forth between matlab and c/c++ too much; there is bound to be some overhead to converting the datatypes and invoking the MCR. All I really use it for is wrapping up a complex but self-contained matlab script (i.e.: doesn't need to interact with the c/c++ code mid way through said script) as a function, or packaging up code for deployment to environments which don't have a full copy of matlab.

    As an interesting side note: if you are calling C++ from within Matlab, and that C++ code needs access to a global variable, things are much easier. You can simply do this by wrapping your C++ code into a mexFunction and compiling that. In the places you need to access a variable which is in the Matlab workspace, you can do so using the mexGetVariablePtr which will return a read-only pointer to the data. The variable you are accessing can be in either the global workspace, or that of the function which called your mexFunction.

    With this approach I would suggest liberally comment the variable that you are getting in both the C++ and Matlab code, as the link between them may not be obvious from the Matlab side; you wouldn't want someone to come along later, edit the script and wonder why it had broken.

    In this case it seems that the C++ side doesn't really need access to the data, so you could refactor it to have matlab do the calling by wrapping the "get current position of fingers" code into a mexFunction, then have matlab do the loop:

    data = loadData();
    while(~stop) {
      position = getFingerPositionMex();
      soundByCoef(position, data);
    }
    

    Assuming you don't modify the data within soundByCoef Matlab will use pass by reference, so there will be no copying of the large dataset.

    0 讨论(0)
  • 2020-12-19 15:02

    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

    0 讨论(0)
提交回复
热议问题