Main Content

Deploy MATLAB Function to C++ Application Using MATLAB Data API

This example shows how to package a MATLAB® function and deploy it within a C++ application. It uses the MATLAB Data API for managing data exchange between the MATLAB function and the C++ application. The workflow is supported on Windows®, Linux®, and macOS.

Prerequisites

  • Create a new work folder that is visible to the MATLAB search path. This example uses a folder named work.

  • Verify that you have set up a C++ development environment. For details, see Setting Up C++ Development Environment. This example uses MATLAB as a C++ development environment. Therefore, verify that you have a C++ compiler installed by typing mbuild -setup at the MATLAB command prompt.

  • Verify that you have met all of the MATLAB Compiler SDK™ C++ target requirements. For details, see MATLAB Compiler SDK C++ Target Requirements.

  • End users must have an installation of MATLAB Runtime to run the application. For details, see Install and Configure MATLAB Runtime.

    For testing purposes, you can use an installation of MATLAB instead of MATLAB Runtime when running the C++ application.

Create MATLAB Function

Create a MATLAB file named calculateDistance.m with the following code:

function distance = calculateDistance(p1, p2)
    % This function calculates the Euclidean distance between two points
    % Inputs:
    %   p1 - a two-element vector [x, y]
    %   p2 - a two-element vector [x, y]
    % Output:
    %   distance - the Euclidean distance between p1 and p2
    
    % Use arguments block to map C++ type to corresponding MATLAB type
    % std::vector<int32_t> <--> (1,2) int32 {mustBeReal}
    
    arguments (Input)
        p1 (1,2) int32 {mustBeReal}
        p2 (1,2) int32 {mustBeReal}
    end

    arguments (Output)
        distance (1,1) int32 {mustBeReal}
    end
    
    % Calculte Euclidean distance
    diff = p1 - p2;
    diffSq = diff.^2;
    sumSq = sum(diffSq);
    distance = sqrt(sumSq);
end

Established MATLAB users may find the presence of an arguments block unconventional. The arguments block lets you represent C++ data types with an equivalent MATLAB type. For instance, if your C++ application employs an int32_t data type representing a value, you can now represent that in MATLAB as an int32. This option is useful in situations where a C++ application has strict type requirements. For details, see Data Type Mappings Between C++ and Strongly Typed MATLAB Code.

In this example, an arguments block with specified type information is used to illuminate subtle nuances. However, remember that incorporating an arguments block is entirely optional. The deployment process remains unchanged even without it. Various parts of this example underscore the areas where this difference manifests. So, if data types aren't crucial, the specification of type information using an arguments block is not necessary.

Test the MATLAB function at the command prompt.

p1 = int32([0, 0])
p2 = int32([3 4])
distance = calculateDistance(p1,p2)
p1 =
  1×2 int32 row vector
   0   0
p2 =
  1×2 int32 row vector
   3   4
distance =
  int32
   5

Note

MATLAB

functions that use varargin and varargout are unsupported.

Package MATLAB Function Using compiler.build.cppSharedLibrary

Create a code archive (.ctf file) and header (.hpp file) from the MATLAB function using the compiler.build.cppSharedLibrary function.

buildResults = compiler.build.cppSharedLibrary("calculateDistance.m",...
    OutputDir=".\output", Verbose="on");

The function produces a suite of files, as enumerated below, and places them in the specified output directory. Among these, the key files utilized during the integration process are the code archive (.ctf file) containing the MATLAB code and the corresponding header (.hpp file). For information on the other files, see Files Generated After Packaging MATLAB Functions.

P:\MATLAB\WORK\OUTPUT
│   GettingStarted.html
│   includedSupportPackages.txt
│   mccExcludedFiles.log
│   readme.txt
│   requiredMCRProducts.txt
│   unresolvedSymbols.txt
│
└───v2
    └───generic_interface
            calculateDistance.ctf
            calculateDistancev2.hpp
            readme.txt

To finalize integration, you need the calculateDistance.ctf code archive file and the calculateDistancev2.hpp header file from the generic_interface folder. You can view the header file here:

 calculateDistancev2.hpp

In the calculateDistancev2.hpp header, the MATLAB function's int32 argument specification mirrors its C++ equivalent, int32_t.

    arguments (Input)
        p1 (1,2) int32 {mustBeReal}
        p2 (1,2) int32 {mustBeReal}
    end
   
std::vector<int32_t> p1, 
std::vector<int32_t> p2)
    arguments (Output)
        distance (1,1) int32 {mustBeReal}
    end
template<>
struct return_type_calculateDistance<1> { typedef int32_t type; };
...
...
matlab::data::Array _result_mda = _matlabPtr->feval(u"calculateDistance", _args);
int32_t _result;
_result = MatlabTypesInterface::convertMDAtoScalar<int32_t>(_result_mda);

When an arguments block detailing type information is not included in your MATLAB function, it results in the production of the following header file:

 calculateDistancev2.hpp (Type Agnostic)

The primary difference between the header files rests in the type specification for input and output variables. When an arguments block is used with type information specified, the inputs and outputs are categorized as std::vector<int32_t> and int32_t respectively. Conversely, when an arguments block is absent, the inputs and outputs receive a matlab::data::Array object type designation.

Note

The generated artifacts do not include MATLAB Runtime or an installer. To create an installer using the buildResults object, see compiler.package.installer.

Integrate MATLAB Code Archive into C++ Application

You can finalize the integration process in your preferred C++ development environment, including MATLAB or alternatives such as Microsoft® Visual Studio® on Windows. This example, however, uses MATLAB as a C++ development environment. For details, see Setting Up C++ Development Environment.

To integrate the generated MATLAB code archive (.ctf file) and header (.hpp file) into a C++ application, adhere to these guidelines:

  • Use a #include directive to incorporate the generated header file (.hpp file) in your C++ application code.

  • Ensure the code archive (.ctf file) is positioned in a location that the C++ executable can access.

Completing the integration step requires proficient C++ skills for writing application code. You can use the following sample C++ application code as guide when writing your own application.

  1. In the work folder for this example create a new file named DistanceConsoleApp.cpp with the following code.

     DistanceConsoleApp.cpp

    When an arguments block detailing type information is not included in your MATLAB function, your C++ application code must be written as follows:

     DistanceConsoleApp.cpp (Type Agnostic)

    In C++ application code, the distinction between including an arguments block with type information and not doing so lies in the specification of inputs and outputs to the MATLAB function. When an arguments block detailing type information is included, the use of C++ Standard Library and primitive types is permissible for input and output specification. On the other hand, when an arguments block detailing type information is not included, inputs and outputs must be defined as matlab::data::Array objects.

  2. Compile and link the application by executing the mbuild function at the MATLAB command prompt.

    mbuild -v DistanceConsoleApp.cpp -outdir output\bin

Handle Code Archive (.ctf file)

To ensure your C++ application can access the code archive (.ctf file) containing MATLAB code, place the file in a location accessible to the executable. For this example we are going to do this by setting the CPPSHARED_BASE_CTF_PATH environment variable in the MATLAB desktop environment.

setenv("CPPSHARED_BASE_CTF_PATH","P:\MATLAB\work\output\v2\generic_interface")

If you're using Visual Studio, see Setting Environment Variable in Visual Studio.

For a complete list of code archive (.ctf file) placement options, see Code Archive (.ctf file) Placement.

Run C++ Application

For testing purposes, you can run the application from MATLAB command prompt. This does not require a MATLAB Runtime installation.

!output\bin\DistanceConsoleApp.exe
Euclidean distance between [0, 0] and [3, 4] is: 5

Subtleties of Deploying to C++ Using MATLAB Data API

  • When deploying MATLAB code to a C++ application using the MATLAB Data API, MATLAB Compiler SDK does not generate a C++ shared library. The primary outputs from the compiler.build.cppSharedLibrary function or the Library Compiler app are a code archive (.ctf file) and a header file(.hpp file). If you want MATLAB Compiler SDK to generate a C++ shared library from MATLAB code, you need to use the mwArray API. However, this API uses the older C++03 standard, lacking many of the modern features offered by the MATLAB Data API, which is built upon the more current C++11 standard.

  • Since R2021b, MATLAB Compiler SDK has supported argument type specification, albeit exclusively for input arguments. Within a MATLAB function, the data types for output arguments were derived from the type specifications and interactions of various functions inside the function. As a result, the output type was always mapped to a matlab::data::Array object in C++.

  • Since R2023b, argument type specification is supported for both input and output arguments. Inside a MATLAB function, the type specifications and interactions of various functions continue to determine the resulting output type. However, when this output is returned to the C++ application, it is cast to the type that the C++ application needs. This casting is managed in the generated header (.hpp file).

    Consider the calculateDistance function in the calculateDistance.m file. This function performs four operations to compute the Euclidean distance:

    diff = p1 - p2;
    diffSq = diff.^2;
    sumSq = sum(diffSq);
    distance = sqrt(sumSq);

    When providing two inputs to this function, say p1 = int32([0, 0]) and p2 = int32([3 4]), the int32 type is maintained until the sum function executes. After execution, sumSq changes to a double type. Consequently, when sqrt executes, the output argument distance also becomes a double.

    Review the last few lines of the calculateDistancev2.hpp header:

    matlab::data::Array _result_mda = _matlabPtr->feval(u"calculateDistance", _args);
    int32_t _result;
    _result = MatlabTypesInterface::convertMDAtoScalar<int32_t>(_result_mda);
    return _result;

    When examining the final lines of the calculateDistancev2.hpp file, we observe the feval call to the MATLAB function calculateDistance. The result of this function call is stored in the variable _result_mda, which is an object of type matlab::data::Array.

    Subsequently, a new variable _result is declared as an int32_t type. In the following line, the _result_mda variable, which originally was a matlab::data::Array type, undergoes a conversion to int32_t. This conversion is achieved through the convertMDAtoScalar<int32_t>() function, a part of the MatlabTypesInterface library.

    Finally, _result is returned by the function. This return value is a scalar integer (an int32_t), which was converted from a MATLAB array.

    Given two new points p1 and p2 represented as int32 arrays with values [0,0] and [3, 7] respectively, the calculateDistance MATLAB function computes the Euclidean distance between these points. In this particular case, the calculated distance is 7.6158, a value with double data type.

    However, when this result is returned to the C++ application, a type conversion occurs. Specifically, the double result is converted to an int32_t type. As a result of this conversion process, the original double value 7.6158 gets rounded up to 8, which is then received by the C++ application as an int32_t.

    This demonstrates how type conversions between MATLAB and C++ can affect the precision of data. It's crucial to be aware of these potential rounding issues when designing and interfacing between MATLAB functions and C++ applications.

  • It's important to remember that employing an arguments block to specify type information in MATLAB functions is not mandatory—it's a feature to be utilized solely based on the specific requirements of your C++ application. However, this feature offers several benefits which should not be overlooked.

    The ability to define types in a MATLAB function allows for more precise control over the data types returned to the C++ application from MATLAB functions. This reduces the need for additional type conversions within the C++ code, which can often be a source of performance inefficiency and potential bugs.

    In essence, this feature facilitates a smoother integration of MATLAB code within C++ applications. By specifying the data types directly in MATLAB, developers can streamline the process of interfacing between the two languages.

See Also

| |

Related Topics