Main Content

Conditional Inclusions (#if / #endif)

You can generate preprocessor conditional directives in your code by implementing variants in your model. In the generated code, the preprocessor conditional directives select a section of code to execute at compile time.

This example uses Simulink.Variant objects to control Variant Subsystem blocks. For information about other ways to control variants, see Variant Control Modes in Variant Blocks. For information about types of variants other than Variant Subsystem blocks, see What Are Variants and When to Use Them.

Inspect Model

Open the example model PreprocessorConditionalsUsingVariantSubsystem.

model = 'PreprocessorConditionalsUsingVariantSubsystem';
open_system(model);

Capture.PNG

This model contains two variant subsystems, LeftController and RightController, each with two child subsystems, Linear and Nonlinear. The PostLoadFcn callback function of the model loads rtwdemo_preprocessor_data.mat. To view the callback function, from the Simulink toolstrip, click the Modeling tab and, in the Setup section, click Model Settings > Model Properties. In the Model Properties dialog box, open the Callbacks tab and select PostLoadFcn. Alternatively, view the callback function programmatically.

get_param(model,'PostLoadFcn')
ans = 
'load preprocessor_data.mat'

The callback function instantiates two Simulink.Variant objects, LINEAR and NONLINEAR, and one Simulink.Parameter, VSSMODE. The LINEAR variant is active when VSSMODE is equal to 0. The NONLINEAR variant is active when VSSMODE is equal to 1. VSSMODE is initialized to 1. Verify these settings programmatically.

LINEAR.Condition
ans = 
'VSSMODE==0'
NONLINEAR.Condition
ans = 
'VSSMODE==1'
VSSMODE.Value
ans = int32

1

LeftController and RightController use LINEAR and NONLINEAR as the variant control expressions for their respective Linear and Nonlinear subsystems. To view this configuration, right-click LeftController and click Block Parameters (Subsystem). Alternatively, view the variant control expressions programmatically.

choices = get_param(append(model,'/LeftController'),'VariantChoices');
choices(1)
ans = struct with fields:
         Name: 'LINEAR'
    BlockName: 'PreprocessorConditionalsUsingVariantSubsystem/LeftController/Linear'

choices(2)
ans = struct with fields:
         Name: 'NONLINEAR'
    BlockName: 'PreprocessorConditionalsUsingVariantSubsystem/LeftController/Nonlinear'

Configure Model

Open the Configuration Parameters dialog box. In the left pane, click Code Generation, then confirm System target file is set to ert.tlc. Alternatively, set the parameter programmatically.

set_param(model,'SystemTargetFile','ert.tlc');

In the left pane, click Interface. Confirm the Ignore custom storage classes parameter is cleared. Alternatively, clear the parameter programmatically.

set_param(model,'IgnoreCustomStorageClasses','off');

To generate preprocessor conditionals, use custom storage classes.

Open the Block Parameters dialog box for the LeftController subsystem. Verify the Variant activation time parameter is set to code compile. Alternatively, set the parameter programmatically.

set_param(append(model,'/LeftController'),'VariantActivationTime','code compile');

Open the LeftController subsystem. For each child subsystem, click the subsystem and, in the Subsystem Block tab, confirm Atomic Subsystem is selected. Alternatively, set the parameters programmatically.

set_param(append(model,'/LeftController/Linear'),'TreatAsAtomicUnit','on');
set_param(append(model,'/LeftController/Nonlinear'),'TreatAsAtomicUnit','on');

Generate code.

slbuild(model);
### Starting build procedure for: PreprocessorConditionalsUsingVariantSubsystem
### Successful completion of build procedure for: PreprocessorConditionalsUsingVariantSubsystem

Build Summary

Top model targets:

Model                                          Build Reason                                         Status                        Build Duration
================================================================================================================================================
PreprocessorConditionalsUsingVariantSubsystem  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 13.98s  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 15.242s

View the generated code. The generated code includes #if and #endif preprocessor directives that use LINEAR and NONLINEAR to select one variant to compile.

cfile = fullfile('PreprocessorConditionalsUsingVariantSubsystem_ert_rtw','PreprocessorConditionalsUsingVariantSubsystem.c');
coder.example.extractLines(cfile,"  /* Outputs for Atomic SubSystem: '<Root>/LeftController' */",...
    "  /* End of Outputs for SubSystem: '<Root>/LeftController' */", 1, 1);
  /* Outputs for Atomic SubSystem: '<Root>/LeftController' */
#if LINEAR

  /* Outputs for Atomic SubSystem: '<S1>/Linear' */
  /* VariantMerge generated from: '<S1>/Out1' incorporates:
   *  DiscreteFilter: '<S3>/Discrete Filter'
   */
  rtY.Out1 = rtb_Add - 0.5 * rtDWork.DiscreteFilter_states_a;

  /* Update for DiscreteFilter: '<S3>/Discrete Filter' */
  rtDWork.DiscreteFilter_states_a = rtY.Out1;

  /* End of Outputs for SubSystem: '<S1>/Linear' */
#elif NONLINEAR

  /* Outputs for Atomic SubSystem: '<S1>/Nonlinear' */
  /* VariantMerge generated from: '<S1>/Out1' incorporates:
   *  DiscreteFilter: '<S4>/Discrete Filter'
   *  Lookup_n-D: '<S4>/Lookup Table'
   *  Sum: '<Root>/Add'
   */
  rtY.Out1 = look1_binlxpw(rtb_Add, rtCP_LookupTable_bp01Data,
    rtCP_LookupTable_tableData, 4U) - 0.5 * rtDWork.DiscreteFilter_states_o;

  /* Update for DiscreteFilter: '<S4>/Discrete Filter' */
  rtDWork.DiscreteFilter_states_o = rtY.Out1;

  /* End of Outputs for SubSystem: '<S1>/Nonlinear' */
#endif

Related Topics