Main Content

Pass C++ Structures to Deployed MATLAB Functions

Since R2024b

This example shows how to pass C++ structures to a MATLAB® function deployed within a C++ application. The workflow is supported on Windows®, Linux®, and macOS systems.

To pass C++ structs to MATLAB functions, in your application code, you must start MATLAB Runtime in IN_PROCESS mode. You need to use the USING_TYPE_WITH_MATLAB macro to inform MATLAB about the custom C++ types, ensuring proper recognition and handling during function calls. Additionally, you must use the matlab::cpplib::MATLABLibrary::feval method in your C++ code to evaluate and execute the MATLAB functions when passing these structures.

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 Set 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 C++ 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 Download and Install MATLAB Runtime.

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

Create C++ Header File Containing Namespace and Struct Definitions

Create a header file named cppstruct.hpp that includes a namespace and structure definitions for the data you want to pass to the deployed MATLAB function.

#include <vector>
#include <string>
#include <map>

// Define a namespace for the struct definitions
namespace cppstruct {

    // Define a struct for the input data
    struct InputStruct {
        std::vector<double> temperatures;
        std::vector<double> pressures;
    };

    // Define a struct for the statistical results of each field
    struct FieldStats {
        double mean;
        double std;
        double max;
    };

    // Define a struct for the output data
    struct OutputStruct {
        FieldStats temperatures;
        FieldStats pressures;
    };

}

The cppstruct.hpp header file defines a namespace cppstruct that contains three structures: InputStruct, FieldStats, and OutputStruct.

  • InputStruct holds vectors of temperature and pressure data.

  • FieldStats stores the following statistical results for a field: mean, standard deviation, and maximum value.

  • OutputStruct is a nested structure that contains FieldStats for both temperatures and pressures.

Generate MATLAB Interface to C++ Header File

Generate a MATLAB interface for the C++ header file named cppstruct.hpp using the clibgen.buildInterface function. In this particular case, we chose to name the interface data, but in other cases, you can use different names.

clibgen.buildInterface("cppstruct.hpp", InterfaceName="data")

This creates a folder named data and generates a DLL named dataInterface.dll. The clibgen.buildInterface function follows the convention of appending the word Interface to the interface name you provide.

Add Interface to MATLAB Path

To use the C++ structures in your MATLAB code, add the interface folder to the MATLAB path.

addpath("P:\MATLAB\work\data")

Create MATLAB Function

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

function outputStruct = analyzeData(inputStruct)
% analyzeData Analyzes numeric fields in a C++ struct and returns
% statistical measures.
%
% This function takes 'inputStruct' as input, which is a MATLAB
% representation of a C++ struct. This representation is generated using
% the clibgen.buildInterface function. The function performs statistical
% analysis on each numeric field within the struct and returns the results
% in a new struct 'outputStruct'. The analyses include computing the mean,
% standard deviation, and maximum value for each numeric field.
%
% Inputs:
%   inputStruct - A MATLAB representation of a C++ struct
%   (clib.data.cppstruct.InputStruct) that has temperature and pressure
%   data. It contains the fields: 
%   - temperatures: a clib.array.data.Double array of temperature values 
%   - pressures: a clib.array.data.Double array of pressure values
%
% Outputs:
%   outputStruct - A MATLAB representation of a C++ struct
%   (clib.data.cppstruct.OutputStruct) with the same fields as
%   'inputStruct'. For each numerical array in 'inputStruct', the
%   corresponding field in 'outputStruct' is a struct containing:
%   - mean: Mean value of the numerical array 
%   - std: Standard deviation of the numerical array 
%   - max: Maximum value of the numerical array


arguments (Input)
    inputStruct (1,1) clib.data.cppstruct.InputStruct
end

arguments (Output)
    outputStruct (1,1) clib.data.cppstruct.OutputStruct
end

% Initialize outputStruct
outputStruct = clib.data.cppstruct.OutputStruct;

% Perform analysis on 'temperatures' field
if isa(inputStruct.temperatures, 'clib.array.data.Double')
    % Cast C++ clib.array.data.Double array to MATLAB double array
    doubleTemperatures = double(inputStruct.temperatures);
    
    % Calculate mean
    outputStruct.temperatures.mean = mean(doubleTemperatures);
    
    % Calculate standard deviation
    outputStruct.temperatures.std = std(doubleTemperatures);

    % Calculate max value
    outputStruct.temperatures.max = max(doubleTemperatures);
else
    warning('Field temperatures is not numeric and was skipped.');
end

% Perform analysis on 'pressures' field
if isa(inputStruct.pressures, 'clib.array.data.Double')
    % Cast C++ clib.array.data.Double array to MATLAB double array
    doublePressures = double(inputStruct.pressures);
    
    % Calculate mean
    outputStruct.pressures.mean = mean(doublePressures);
    
    % Calculate standard deviation
    outputStruct.pressures.std = std(doublePressures);

    % Calculate max value
    outputStruct.pressures.max = max(doublePressures);
else
    warning('Field pressures is not numeric and was skipped.');
end

end

To use C++ structs in a MATLAB function, you need to specify the argument definitions in the function's arguments block. These definitions indicate that the C++ structs defined in the cppstruct.hpp header file will be used. First, ensure the folder containing the generated MATLAB interface files is added to the MATLAB path. The structures defined in the header file are accessed in MATLAB with the naming convention clib.<interface_name>.<namespace>.<structure_name>. For example, in this case, you use clib.data.cppstruct.InputStruct for the input structure and clib.data.cppstruct.OutputStruct for the output structure.

For details on data type mapping, see C++ to MATLAB Data Type Mapping.

Test the MATLAB function at the command prompt.

input = clib.data.cppstruct.InputStruct;
input.temperatures = [72, 75, 69, 68, 70];
input.pressures = [30, 29.5, 30.2, 29.9, 30.1];
output = analyzeData(input)
disp("Temperatures:")
disp(output.temperatures)
disp("Pressures:")
disp(output.pressures)
output = 
  OutputStruct with properties:

    temperatures: [1×1 clib.data.cppstruct.FieldStats]
       pressures: [1×1 clib.data.cppstruct.FieldStats]
Temperatures:
  FieldStats with properties:

    mean: 70.8000
     std: 2.7749
     max: 75
Pressures:
  FieldStats with properties:

    mean: 29.9400
     std: 0.2702
     max: 30.2000

Package MATLAB Function Using compiler.build.cppSharedLibrary

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

buildResults = compiler.build.cppSharedLibrary("analyzeData.m", ...
    OutputDir=".\output", Verbose="on",...
    AdditionalFiles="P:\MATLAB\work\data\dataInterface.dll");

The interface library dataInterface.dll must be added as a dependent file using the AdditionalFiles name-value pair.

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. 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
            analyzeData.ctf
            analyzeDatav2.hpp
            readme.txt

Note

The analyzeDatav2.hpp header file, which is typically used for working with strongly typed interfaces, is generated but not used in this context.

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 Set Up C++ Development Environment.

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

  • Use a #include directive to incorporate the C++ header file (.hpp file) containing the structure definitions 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 PassCppStructConsoleApp.cpp with the following code.

     PassCppStructConsoleApp.cpp

    IN_PROCESS Mode

    In the application code, you must start MATLAB Runtime in IN_PROCESS mode in order to pass C++ structs to MATLAB functions.

    USING_TYPE_WITH_MATLAB Macro

    The USING_TYPE_WITH_MATLAB macro is used to inform MATLAB about the custom C++ types that will be utilized within the integration. The general form of this macro is USING_TYPE_WITH_MATLAB(namespace::structure_name, "interface_name"), where namespace::structure_name is the fully qualified name of the C++ structure, and interface_name is the name of the interface defined for MATLAB. This setup ensures that MATLAB correctly recognizes and handles these structures during function calls. For instance, in the provided code, the macro is used to map the cppstruct::OutputStruct, cppstruct::InputStruct, and cppstruct::FieldStats types to the interface named data.

    matlab::cpplib::MATLABLibrary::feval Method

    When using the strongly typed interface, you include the generated header file (.hpp file) in your application code, allowing you to directly call MATLAB functions defined in the (.ctf file) from your C++ code. However, when passing C++ structures to deployed MATLAB functions, you cannot call these functions directly. Instead, you must use the matlab::cpplib::MATLABLibrary::feval method in your C++ code to evaluate and execute the MATLAB functions.

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

    mbuild -v PassCppStructConsoleApp.cpp -outdir output\bin

Visual Studio

If you are using Visual Studio for the integration phase, follow the steps in Set Up Microsoft Visual Studio for C++ Development (Windows Only). Additionally, you need to make some changes to ensure your debug build uses the same C/C++ Runtime Library as MATLAB. To do this:

  1. Open Visual Studio and navigate to your project in the Solution Explorer.

  2. Right-click on your project name and select Properties from the context menu.

  3. In the properties window, navigate to Configuration Properties > C/C++ > Preprocessor.

    Remove _DEBUG from the Preprocessor Definitions list.

  4. Navigate to Configuration Properties > C/C++ > Code Generation. Change the Runtime Library setting to Multi-threaded DLL (/MD).

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 Set Environment Variables 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\PassCppStructConsoleApp.exe
Executing MATLAB function ...
Temperatures - Mean: 70.8000, Std: 2.7749, Max: 75.0000
Pressures - Mean: 29.9400, Std: 0.2702, Max: 30.2000

See Also

| | |

Related Topics