Use Multiple Shared Libraries in Single Application

There are a few things you need to consider when developing applications that use multiple MATLAB® shared libraries:

  • each MATLAB shared library must be initialized separately

  • each MATLAB shared library must be terminated separately

  • MATLAB function handles cannot be shared between shared libraries

  • MATLAB figure handles cannot be shared between shared libraries

  • MATLAB objects cannot be shared between shared libraries

  • C, Java®, and .NET objects cannot be shared between shared libraries

  • executable data stored in cell arrays and structures cannot be shared between shared libraries

Initialize and Terminate Multiple Shared Libraries

Initializing and terminating multiple shared libraries follows the same pattern as initializing a single shared library:

  1. Initialize the MATLAB Runtime using mclmcrIntialize().

  2. Call the portion of the application that executes the MATLAB code using mclRunMain().

  3. Before initializing the shared libraries, initialize the MATLAB application state using mclInitializeApplication().

  4. For each MATLAB shared library, call the generated initialization function, libraryInitialize().

  5. Add the code for working with the MATLAB code.

  6. For each MATLAB shared library, release the resources used by the library using the generated termination function, libraryTerminate().

  7. Release the resources used by the MATLAB Runtime by calling mclTerminateApplication().

The following code uses two shared libraries.

#include <stdio.h>
#include "libAddMatrix.h"
#include "libSubMatrix.h"
 
int run_main(int argc, const char *argv[])
{
  
   if( !mclInitializeApplication(NULL,0) )
   {
       fprintf(stderr, "Could not initialize the application.\n");
       return -1;
   }  

   if (!libAddMatrixInitialize())
   {
       fprintf(stderr,"Could not initialize the AddMatrix library.\n");
       return -2;
   }

   if (!libSubMatrixInitialize())
   {
       fprintf(stderr,"Could not initialize the SubMatrix library.\n");
       return -2;
   }

   try
   {
   ...
   }
   catch (const mwException& e)
   {
       std::cerr << e.what() << std::endl;
       return -2;
   }
   catch (...)
   {
       std::cerr << "Unexpected error thrown" << std::endl;
       return -3;
   }

   libAddMatrixTerminate();

   libSubMatrixTerminate();

   mclTerminateApplication();
   return 0;
}
 
int main(int ac, const char *av[])
{
   int err = 0;
   mclmcrInitialize();
   err = mclRunMain((mclMainFcnType) run_main, ac, av);
   return err;
}

Work with MATLAB Function Handles

MATLAB function handles can be passed between an application and the MATLAB Runtime instance from which it originated. However, a MATLAB function handle cannot be passed into a MATLAB Runtime instance other than the one in which it originated. For example, suppose you had two MATLAB functions, get_plot_handle and plot_xy, and plot_xy used the function handle created by get_plot_handle.

% Saved as get_plot_handle.m
function h = get_plot_handle(lnSpec, lnWidth, mkEdge, mkFace, mkSize)
h = @draw_plot;
    function draw_plot(x, y)
        plot(x, y, lnSpec, ...
            'LineWidth', lnWidth, ...
            'MarkerEdgeColor', mkEdge, ...
            'MarkerFaceColor', mkFace, ...
            'MarkerSize', mkSize)
    end
end
% Saved as plot_xy.m
function plot_xy(x, y, h)
h(x, y);
end

If you compiled them into two shared libraries, the call to plot_xy would through an exception.

#include <stdio.h>
#include "get_plot_handle.h"
#include "plot_xy.h"
 
int run_main(int argc, const char *argv[])
{
  
   if( !mclInitializeApplication(NULL,0) )
   {
       fprintf(stderr, "Could not initialize the application.\n");
       return -1;
   }  

   if (!get_plot_handleInitialize())
   {
       fprintf(stderr,
         "Could not initialize the get_plot_handle library.\n");
       return -2;
   }

   if (!plot_xyInitialize())
   {
       fprintf(stderr,"Could not initialize the plot_xy library.\n");
       return -2;
   }

   try
   {
     mwArray lnSpec('--rs');
     mwArray lnWidth;
     lnWidth = 2.0;
     mwArray mkEdge('k');
     mwArray mkFace('g');
     mwArray mkSize;
     mkSize = 10.0;
     mwArray plot;
     get_plot_handle(1, plot, lnSpec, lnWidth, mkEdge, mkFace, mkSize);

     double x_data[] = {1,2,3,4,5,6,7,8,9};
     double y_data[] = {2,6,12,20,30,42,56,72,90};
     mwArray x(9, 1, mxDOUBLE_CLASS, mxREAL);
     mwArray y(9, 1, mxDOUBLE_CLASS, mxREAL);
     x.SetData(x_data, 9);
     y.SetData(y_data, 9);
     ploy_xy(x, y, plot);
   }
   catch (const mwException& e)
   {
       std::cerr << e.what() << std::endl;
       return -2;
   }
   catch (...)
   {
       std::cerr << "Unexpected error thrown" << std::endl;
       return -3;
   }

   get_plot_handleTerminate();

   plot_xyTerminate();

   mclTerminateApplication();
   return 0;
}
 
int main(int ac, const char *av[])
{
   int err = 0;
   mclmcrInitialize();
   err = mclRunMain((mclMainFcnType) run_main, ac, av);
   return err;
}

One way to handle the situation is to compile both functions into a single shared library. For example, if you called the shared library plot_functions, your application would only need one call to initialize the functions and you could pass the function handle for plot_xy without error.

#include <stdio.h>
#include "get_plot_handle.h"
#include "plot_xy.h"
 
int run_main(int argc, const char *argv[])
{
  
   if( !mclInitializeApplication(NULL,0) )
   {
       fprintf(stderr, "Could not initialize the application.\n");
       return -1;
   }  

   if (plot_functionsInitialize())
   {
       fprintf(stderr,
         "Could not initialize the plot_functions library.\n");
       return -2;
   }

   try
   {
     mwArray lnSpec('--rs');
     mwArray lnWidth;
     lnWidth = 2.0;
     mwArray mkEdge('k');
     mwArray mkFace('g');
     mwArray mkSize;
     mkSize = 10.0;
     mwArray plot;
     get_plot_handle(1, plot, lnSpec, lnWidth, mkEdge, mkFace, mkSize);

     double x_data[] = {1,2,3,4,5,6,7,8,9};
     double y_data[] = {2,6,12,20,30,42,56,72,90};
     mwArray x(9, 1, mxDOUBLE_CLASS, mxREAL);
     mwArray y(9, 1, mxDOUBLE_CLASS, mxREAL);
     x.SetData(x_data, 9);
     y.SetData(y_data, 9);
     ploy_xy(x, y, plot);
   }
   catch (const mwException& e)
   {
       std::cerr << e.what() << std::endl;
       return -2;
   }
   catch (...)
   {
       std::cerr << "Unexpected error thrown" << std::endl;
       return -3;
   }

   plot_functionsTerminate();

   mclTerminateApplication();
   return 0;
}
 
int main(int ac, const char *av[])
{
   int err = 0;
   mclmcrInitialize();
   err = mclRunMain((mclMainFcnType) run_main, ac, av);
   return err;
}

Work with Objects

MATLAB Compiler SDK™ allows you to return the following types of objects from the MATLAB Runtime to your application code:

  • MATLAB

  • C++

  • .NET

  • Java

However, you cannot pass an object created in one MATLAB Runtime instance into a different MATLAB Runtime instance. This can happen when functions that return an object and a function that manipulates that object are compiled into different shared libraries.

For example, you develop two functions. The first creates a bank account for a customer based on some set of conditions. The second transfers funds between two accounts.

% Saved as account.m
classdef account < handle

    properties
        name
    end
    
    properties (SetAccess = protected)
        balance = 0
        number
    end
    
    methods
        function obj = account(name)
            obj.name = name;
            obj.number = round(rand * 1000);
        end
        
        function deposit(obj, deposit)
            new_bal = obj.balance + deposit;
            obj.balance = new_bal;
        end
        
        function withdraw(obj, withdrawl)
            new_bal = obj.balance - withdrawl;
            obj.balance = new_bal;
        end
        
    end
end
% Saved as open_acct .m
function acct = open_acct(name, open_bal )

    acct = account(name);

    if open_bal > 0
        acct.deposit(open_bal);
    end
    
end
% Saved as transfer.m
function transfer(source, dest, amount)

    if (source.balance > amount)
        dest.deposit(amount);
        source.withdraw(amount);
    end

end

If you compiled open_acct.m and transfer.m into separate shared libraries, you could not transfer funds using accounts created with open_acct. The call to transfer throws an exception. One way of resolving this is to compile both functions into a single shared library. You could also refactor the application such that you are not passing MATLAB objects to the functions.

Was this topic helpful?