Generate C++ Executable for Entry-Point System Object in a Namespace (Tech Preview)
This example shows how to use a System object™ in a namespace as an entry point for C++ code generation. The code generator produces an C++ class that you can access directly from your external C++ code. You then create a C++ executable that uses the generated C++ class.
Note
Using a MATLAB® class as an entry point for code generation is a tech preview. This
feature is in active development and may change between the tech preview and the general
release. The primary purpose of the tech preview is to solicit feedback from users. To
enable the feature, enter enableCodegenForEntryPointClasses at the
command line before calling the codegen function or creating a coder.Type object in a MATLAB session. To provide feedback, email the
development team or participate
in a survey.
Enable Feature and Create MATLAB Class
First, enable code generation for entry-point classes.
enableCodegenForEntryPointClasses
=== Code generation for entry-point classes is ENABLED ===
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 default value of
StepSize is 1. The
MyCounter class implements the protected method
stepImpl, which increments the counter. The System object
step method invokes the stepImpl method. The
MyCounter class also implements the protected
setupImpl and resetImpl methods, which
respectively initialize and reset the counter. 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. MATLAB creates a coder.ClassSignature object that includes
the name of the
namespace.
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 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 methods 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: 1Specify 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 further
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
TargetLangproperty to"C++". See Language.To instruct the code generator to contain the C++ code it generates in the namespace
allCode, set theCppNamespaceproperty to"allCode". See C++ namespace.To instruct the code generator to contain the code it generates for MathWorks® code in the namespace
notMyCode, set theCppNamespaceForMathworksCodeproperty 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 with the public property
StepSize. The init methods and the
non-initializing constructor are internal methods. Because these methods may change
in the future, do not use them 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
Create a C++ main function that uses the generated C++ class.
When you generate code for an entry-point class, the code generator does not produce
an example main function.
In this example, the 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_ttag to createcountStepD, which has the default step size of one.
The main function increments each counter twice and displays
the results. Save this file in the working directory 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;
}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 select 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 =
0See Also
addMethod | codegen | coder.ClassSignature | coder.FunctionSignature