Main Content

Generate C++ Executable for Entry-Point System Object in a Namespace

R2026b
Since R2026a

This example shows how to use a System object™ in a namespace as an entry point for C++ code generation. The code generator produces a C++ class that you can access directly from your external code. You then create an executable that uses the generated class.

Note

Using a MATLAB® class as an entry point for code generation is a tech preview. This feature is in active development and might change between the tech preview and the general release. To enable the feature, enter enableCodegenForEntryPointClasses at the command line before launching the MATLAB Coder™ app, calling the codegen function, or creating a coder.Type object. To provide feedback, email the development team or participate in a survey.

Enable Tech Preview

Before you begin, enable code generation for entry-point classes.

enableCodegenForEntryPointClasses
=== Code generation for entry-point classes is ENABLED ===

Create MATLAB Class

This example uses the System object MyCounter. The public MyCounter class constructor method defines a MyCounter object with a step size specified by the public property StepSize.

The MyCounter class implements these protected methods:

  • stepImpl, which increments the counter

  • setupImpl, which initializes the counter

  • resetImpl, which resets the counter

The System object step method invokes the stepImpl method.

Save the MyCounter definition in the namespace +MyNamespace.

classdef MyCounter < matlab.System
    properties
        StepSize = 1
    end

    properties (DiscreteState)
        Count
    end

    methods
        function obj = MyCounter(stepVal)
            if nargin > 0
                obj.StepSize = stepVal;
            end
        end
    end

    methods (Access = protected)
        function setupImpl(obj)
            obj.Count = 0;
        end

        function y = stepImpl(obj)
            obj.Count = obj.Count + obj.StepSize;
            y = obj.Count;
        end

        function resetImpl(obj)
            obj.Count = 0;
        end
    end
end

Define coder.ClassSignature Object

Define a coder.ClassSignature object by using the name of the namespace and the MyCounter class.

classSig = coder.ClassSignature("MyNamespace.MyCounter")
classSig = 

coder.ClassSignature
  1×1 MyNamespace.MyCounter
    TypeName: "MyCounter"
    Properties: struct with no fields.
    Methods: dictionary (string --> cell) with no entries.

Add the public constructor method MyCounter to the classSig object by using the addMethod method. Do not include the namespace in the name of the method, because MATLAB does not store class methods inside namespaces. Specify that the constructor method is polymorphic and accepts one or zero arguments.

addMethod(classSig,"MyCounter",{0});
addMethod(classSig,"MyCounter",{})
ans = 

coder.ClassSignature
  1×1 MyNamespace.MyCounter
    TypeName: "MyCounter"
    Properties: struct with no fields.
    Methods:
      MyCounter:
        (1) Args: {1×1 double}
        (2) Args: {}

The code generator creates two coder.FunctionSignature objects that represent the two signatures of the MyCounter method and adds these objects to the class signature object.

Add the System object step method to the coder.ClassSignature object. Because step can return a variable number of outputs, specify the Nargout name-value argument when you call addMethod.

addMethod(classSig,"step",{classSig},Nargout = 1)
ans = 

coder.ClassSignature
  1×1 MyNamespace.MyCounter
    TypeName: "MyCounter"
    Properties: struct with no fields.
    Methods:
      MyCounter:
        (1) Args: {1×1 double}
        (2) Args: {}
      step:
            Args: {1×1 this}
            Nargout: 1

Generate MEX Function and Test Generated Class

Generate a MEX function from the entry-point class. By default, calling the codegen command on an entry-point class generates a C MEX function with the same name as the MATLAB class in the working folder. Use the -class option to specify the class object, and use the -lang:c++ option to generate C++ code.

codegen -lang:c++ -class classSig
Code generation successful.

When you generate a MEX function for an entry-point class, the generated function contains the class and method definitions. To create an instance of the generated class, invoke the class constructor by passing the name of the constructor to the MEX function, followed by the required inputs.

For this example, construct two instances of the generated class, one with the default step size of 1 and one with a step size of 3. Because the class is inside a namespace, call the constructor method by using dot notation.

MyMexSystObject1 = MyNamespace_MyCounter_mex("MyNamespace.MyCounter");
MyMexSystObject3 = MyNamespace_MyCounter_mex("MyNamespace.MyCounter",3);

To test the generated class, call the step method. The objects increment by the expected amount.

MyMexSystObject1.step
ans = 1
MyMexSystObject1.step
ans = 2
MyMexSystObject3.step
ans = 3
MyMexSystObject3.step
ans = 6

Specify C++ Namespace for Generated Code

You can use the code configuration settings to control how the code generator creates namespaces for the code it generates. See Organize Generated C++ Code into Namespaces.

By default, the code generator produces C++ namespaces for the namespaces in the MATLAB code. In this example, it stores the code it generates for the user-written MATLAB code in the C++ namespace MyNamespace. To control how the code generator partitions the generated C++ code into namespaces, create a code configuration object for a static library and modify these settings:

  • To generate C++ code, set the TargetLang property to "C++". See Language.

  • To instruct the code generator to contain the C++ code it generates in the namespace allCode, set the CppNamespace property to "allCode". See C++ namespace.

  • To instruct the code generator to contain the code it generates for MathWorks® code in the namespace notMyCode, set the CppNamespaceForMathworksCode property to "notMyCode". See Namespace for MathWorks code.

cfg = coder.config("lib");
cfg.TargetLang = "C++";
cfg.CppNamespace = "allCode";
cfg.CppNamespaceForMathworksCode = "notMyCode";

Generate and Inspect Standalone C++ Code

Generate a C++ static library for the MyCounter class by passing the classSig object to the codegen command. Use the -class option to specify the class object, and use the -config option to specify the code configuration object.

codegen -config cfg -class classSig
Code generation successful.

Inspect the definition of the MyCounter class in the generated C++ header file MyNamespace_MyCounter.h.

// Type Definitions
namespace allCode {
namespace MyNamespace {
class MyCounter {
public:
  void init(double stepVal);
  void init();
  double step();
  explicit MyCounter(double stepVal);
  explicit MyCounter(user_construct_tag_t tag);
  MyCounter();
  ~MyCounter();

private:
  void System();

public:
  boolean_T tunablePropertyChanged;
  int isInitialized;
  boolean_T TunablePropsChanged;
  double StepSize;
  double Count;

private:
  boolean_T isSetupComplete;
};

The definition of the MyCounter class is in the namespace MyNamespace, which is in the namespace allCode. The code generator produces three constructor methods:

  • explicit MyCounter(double stepVal), which maps to the constructor that accepts a double value.

  • explicit MyCounter(user_construct_tag_t tag), which maps to the constructor that accepts zero arguments.

  • MyCounter(), which is the non-initializing constructor.

The external C++ application can interact directly with the public MyCounter constructors and the public property StepSize. The init methods and the non-initializing constructor are internal methods. Do not use internal methods in your custom C++ code.

The System method performs operations internal to the generated System object class. The System method uses the public state members tunablePropertyChanged, isInitialized, and TunablePropsChanged to manipulate instances of the C++ class.

Inspect the definition of the MyCounter::init method in the file MyNamespace_MyCounter.cpp.

void MyCounter::init(double stepVal)
{
  System();
  notMyCode::matlab::b_system::coder::SystemProp::matlabCodegenNotifyAnyProp(
      this);
  StepSize = stepVal;
}

The init method uses the method matlabCodegenNotifyAnyProp. Because the code generator produces the C++ code for this method from MathWorks code, the code generator defines the matlabCodegenNotifyAnyProp method in the C++ namespace notMyCode.

Create C++ main Function

When you generate code for an entry-point class, the code generator does not produce an example main function. To generate an executable that uses the generated class, you must write main function for your application.

For example, this C++ main function uses the generated class. Save this code in the working folder as main_MyCounter.cpp.

#include "MyNamespace_MyCounter.h"
#include <iostream>

int main(void) {
    using namespace allCode;
    MyNamespace::MyCounter countStep3{3};
    MyNamespace::MyCounter countStepD{user_construct_tag_t{}};

    std::cout << "MyCounter with StepSize: " << countStep3.StepSize << std::endl;;
    std::cout << "Increment once: " << countStep3.step() << std::endl;
    std::cout << "Increment twice: " << countStep3.step() << std::endl;
   
    std::cout << "MyCounter with StepSize: " << countStepD.StepSize << std::endl;;
    std::cout << "Increment once: " << countStepD.step() << std::endl;
    std::cout << "Increment twice: " << countStepD.step() << std::endl;

    return 0;
}

This main function creates two instances of the MyNamespace::MyCounter class:

  • It uses the constructor that accepts a double value to create countStep3, which has a step size of three.

  • It uses the constructor that accepts the user_construct_tag_t tag to create countStepD, which has the default step size of one.

The main function increments each counter twice and displays the results.

Generate C++ Executable

Generate a C++ executable by using the codegen command. To generate executable code, set the OutputType property of the configuration object to "EXE". See Build type.

cfg.OutputType = "EXE";

Instruct the codegen command to include the main_MyCounter.cpp source code file by specifying the file name on the command line. The code generator creates the MyNamespace_MyCounter executable in the working folder.

codegen -config cfg -class classSig main_MyCounter.cpp;
Code generation successful.

To run the executable in MATLAB, use the system command. Use the ispc function to choose the appropriate system command.

if ispc
    system("MyNamespace_MyCounter.exe")
else
    system("./MyNamespace_MyCounter")
end
MyCounter with StepSize: 3 
Increment once: 3 
Increment twice: 6 
MyCounter with StepSize: 1 
Increment once: 1 
Increment twice: 2 

ans =

     0

See Also

| | |

Topics