The code generator produces code from a Simulink® model containing one or more Variant Subsystem, Variant Model, Variant Source, and Variant Sink blocks. To learn how to create a model containing variant blocks, see Create a Simple Variant Model. To learn how to create a custom Model Advisor check that evaluates the generated code from active and inactive variant paths in a variant system model, see Create Custom Check to Evaluate Active and Inactive Variant Paths from a Model (Simulink Check).
During code generation, a warning related to 'Code generation function packaging' for
the Variant block might be displayed. In the block parameters dialog of the Variant block,
click Code Generation and then select
function from the Function packaging drop-down list
to solve this issue.
Code is generated for different variant choices, the active variant, and the default variant. To generate code for variants, set the following conditions in the Variant Subsystem, Variant Source, or Variant Sink block:
Expression as Variant control
code compile as Variant activation
Code generated for Variant Subsystem blocks is surrounded by
C preprocessor conditionals
#endif. Code generated for Variant Source and
Variant Sink blocks is surrounded by C preprocessor conditionals
Therefore, the active variant is selected at compile time and the
preprocessor conditionals determine which sections of the code to
To construct variant models and generate preprocessor directives in the generated code, see the example Use Variant Models to Generate Code That Uses C Preprocessor Conditionals.
To construct variant subsystems and generate preprocessor directives in the generated code, see the example Use Variant Subsystem To Generate Code That Uses C Preprocessor Conditionals.
To construct models with variant sources and sinks and generate preprocessor directives in the generated code, see the example Represent Variant Source and Sink Blocks in Generated Code.
To generate preprocessor conditionals, the types of blocks that
you can place within the child subsystems of a Variant Subsystem block
are limited. Connections are not allowed in the Variant Subsystem
block diagram. However, during the code generation process, one
is placed at the input of each Outport block within
the Variant Subsystem block diagram. All
of the child subsystems connect to each of the
In the figure below, the code generation process makes the following
connections and adds
VariantMerge blocks to the sldemo_variant_subsystems model.
When compared to a generic Merge block the
can have only one parameter which is the number of Inputs. The
is used for code generation in variant subsystems internally, and
is not available externally to be used in models. The number of inputs
VariantMerge is determined and wired as shown
in the figure below.
The child subsystems of the Variant Subsystem block must be
atomic subsystems. Select Treat as atomic unit parameter
in the Subsystem block parameters dialog, to make the subsystems atomic.
VariantMerge blocks are inserted at the outport
of the subsystems if more than one child subsystems are present. If
the source block of a
VariantMerge block input
is nonvirtual, an error message will be displayed during code generation. You
must make the source block contiguous, by inserting Signal Conversion
blocks inside the variant choices. The signals that enter a Variant
Subsystem block must have the same signal properties (for example,
signal dimensions, port width, and storage class). The
does not support different signal properties because the input ports
and output ports share the same memory. You can use symbolic dimensions
to generate code for a variant subsystem with child subsystems of
different output signal dimensions.
The following components are not conditionally compiled even if only code for variant subsystems or models that are conditionally compiled reference them.
rtModel data structure fields
#include's of utility files
Global constant parameter structure fields that are referenced by multiple subsystems activated by different variants
Parameters that are configured to use an imported, exported, or custom code generation storage class, and are referenced by multiple subsystems that are activated by different variants
Parameters that are configured to use an imported, exported, or custom code generation storage class, and are used by variant model blocks
For modeling patterns in which a Root Inport block connects
to a Variant block with one variant choice, Simulink inserts a hidden
block combination of a Ground block, Signal Conversion block, and
a Variant Merge block. If the variant choice evaluates to false, this
block combination produces an output of
For example, the model
a Variant Source block with one variant choice. When the Variant Control
to true, the input to
Subsystem is a sine wave.
SYSCONST_A==6 evaluates to false, the input
varianttoground.c file contains this
* Sin: '<Root>/Sine Wave' incorporates: * SignalConversion generated from: '<Root>/Subsystem' */ #if SYSCONST_A == 6 Varianttoground_B.VM_Conditional_Signal_Subsystem_0 = sin (Varianttoground_M->Timing.t); #else /* SignalConversion generated from: '<Root>/Subsystem' */ Varianttoground_B.VM_Conditional_Signal_Subsystem_0 = 0.0; #endif /* End of Sin: '<Root>/Sine Wave' */
The comments in the generated code indicate the presence of the hidden signal conversion block. In the hyperlinked comments, you can trace to the original block in the model that triggered the insertion of the hidden block. The code does not contain a comment for the Variant Merge block because this block does not have associated generated code. The Variant Merge block is used internally and is not in the Simulink library.
When a model has variant blocks, the global signals and states are guarded in the generated code with their corresponding variant condition.
Consider a model containing a Variant Source block. The Variant
Source block has conditions
In the generated code, global signals are guarded in declaration, model initialization, and definition of data as shown below.
/* Exported block signals */ #if V == 1 || V == 2 real_T myOutput; /* '<Root>/Gain3' */ #endif
/* exported global signals */ #if V == 1 || V == 2 myOutput = 0.0; #endif
Definition of data:
* Exported Global Signals * * Note: Exported global signals are block signals with an exported global * storage class designation. Code generation will declare the memory for * these signals and export their symbols. * */ #if V == 1 || V == 2 extern real_T myOutput; /* '<Root>/Gain3' */ #endif
When you generate code for a model containing variant blocks, the parameters are guarded in the generated code.
Consider a model with Constant block attached to a Variant Source block.
In the generated code, the parameter of the Constant block is guarded in header file as shown below.
/* Exported data definition */ /* Const memory section */ /* Definition for custom storage class: Const */ #if V == 2 const int32_T Parameter2 = 1; #endif
When a model has Model Reference blocks that are conditional due to inline variants, the header file and the instances referring to the Model Reference blocks are guarded.
Consider this model with two Model References blocks that are conditional due to inline variants.
When you generate code for this model, the header file and instances referring to the Model Reference blocks are guarded as shown in the code below.
#include "mWithTwoModelBlocks_Top_types.h" #include "multiword_types.h" #if (A == 1) //Guarding #define mWithTwoModelBlocks_Ref2_MDLREF_HIDE_CHILD_ #include "mWithTwoModelBlocks_Ref2.h" #endif #if (B == 1) //Guarding #include "mWithTwoModelBlocks_Ref1.h" #endif
When a model has an S-Function block that is conditional due to any connected variant blocks, Simulink guards the header files associated with the S-Function block with the corresponding variant condition in the generated code.
Consider a model with an S-Function block connected to a Variant Source block. In the generated code, the header file is guarded with the variant condition.
#ifndef mSFunctionInclude_COMMON_INCLUDES_ #define mSFunctionInclude_COMMON_INCLUDES_ #include "rtwtypes.h" #include "rt_logging.h" #if V == 1 //Guarding #include "myHeader.h" #endif #endif /* mSFunctionInclude_COMMON_INCLUDES_ */