Generate Shared Utility Code
When to Generate Shared Utility Code
Blocks in a model can require common functionality to implement their algorithms. Consider modularizing this functionality into standalone support or helper functions. This approach can be more efficient than inlining the code for the functionality for each block instance. To decide about using a library or a shared utility, consider:
Packaging functions that can have multiple callers into a library when the functions are defined statically. That is, before you use the code generator to produce code for your model, the function source code exists in a file.
Packaging functions that can have multiple callers as shared utilities (produced during code generation) when the functions cannot be defined statically. For example, several model- and block-specific properties specify which functions are used and their behavior. Also, these properties determine type definitions (for example,
typedef
) in shared utility header files. The number of possible combinations of properties that determine unique behavior make it impractical to define statically the possible function files before code generation.
Configure Naming of Generated Functions
Configure a default naming rule for generated shared utility functions by using one of these methods.
Configuration | Action |
---|---|
A new model or an existing model for which you have mapped default customization settings by using the Code Mappings Editor – C or code mappings programming interface | In the Embedded Coder Dictionary, define a function customization template that specifies a custom function naming rule. Then, in the Code Mappings editor or by using the code mappings programming interface, map the Shared utility function category to that template. For more information, see Configure Default C Code Generation for Categories of Data Elements and Functions. |
A model created in a release earlier than R2018a and that has not been configured with the Code Mappings Editor – C or code mappings programming interface | Set the model configuration parameter Shared utilities identifier format
(CustomSymbolsStrUtil ) to a custom function naming rule. For more
information, see Identifier Format Control. |
Once you use the Code Mappings Editor – C or code mappings programming interface to configure a model, setting model configuration parameter Shared utilities identifier format does not impact code generation. This setting is not applicable for models configured with these specifications.
System Target File | Programming Language |
---|---|
ert.tlc | C++ |
autosar.tlc | C |
autosar_adaptive.tlc | C++ |
The naming rule for shared utility functions must include the
conditional checksum token $C
. To customize the length
of the checksum that the code generator produces, use parameter
Shared checksum length
(SharedChecksumLength
). Increasing the length of the
checksum reduces the probability of clashes.
This example shows the customization of shared utility function names for C code generation.
Open the example model
ConfigurationInterface
.openExample('ConfigurationInterface')
Open the Embedded Coder app.
Set model configuration parameter Shared code placement to
Shared location
.Open the Embedded Coder Dictionary. On the C Code tab, select Code Interface > Embedded Coder Dictionary.
Select Function Customization Template and click Create to add a new function customization template.
For the function customization template, specify these configurations:
Name:
exSharedUtility
Function Naming Rule:
mymodel_$N$C
You can customize this format by using a string. You must include token
$C
.
Open the Code Mappings editor. On the C Code tab, select Code Interface > Default Code Mappings.
On the Function Defaults tab, for the Shared Utility category, configure Function Customization Template as
exSharedUtility
.Generate code and a code generation report.
In the left navigation pane of the report, review the list of generated files for shared utilities under Shared files.
Control Placement of Shared Utility Code
Control placement of shared utility code with the model configuration parameter
Shared code placement. The default option value is
Auto
. For this setting, the code generator places required code
for fixed-point and other utilities in the
file, the
model
.c
file, or a separate file in the
build folder (for example, model
.cppvdp_grt_rtw
) if a model does not contain
existing shared utility code or one of these blocks:
Model blocks
Simulink Function blocks
Function Caller blocks
Calls to Simulink Functions from Stateflow or MATLAB Function blocks
Stateflow graphical functions when you select parameter Export Chart Level Functions
If a model contains one or more of the preceding blocks, the code generator creates and
uses a shared utilities folder within slprj
. The naming convention for
shared utility folders is
slprj/
target
/_sharedutils
.
target
is sim
for simulations with
Model blocks or the name of the system target file for code
generation.
slprj/sim/_sharedutils % folder used with simulation slprj/grt/_sharedutils % folder used with grt.tlc STF slprj/ert/_sharedutils % folder used with ert.tlc STF slprj/mytarget/_sharedutils % folder used with mytarget.tlc STF
To force a model build to use the slprj
folder for shared utility
generation, even when the current model does not contain existing shared utility code or one
of the preceding blocks, set parameter Shared code placement to
Shared location
. The code generator places utilities under the
slprj
folder rather than in the normal build folder. This setting is
useful when you are manually combining code from several models, because it prevents symbol
collisions between the models.
Control Placement of rtwtypes.h for Shared Utility Code
When the configuration parameter Data type replacement is set to
Use coder typedefs
, the generated rtwtypes.h
header file provides fundamental type definitions, #define
statements, and
enumerations. For more information, see rtwtypes.h.
Control placement of rtwtypes.h file by selecting whether the build process uses the
shared utilities folder. If the model build uses a shared utilities folder, the build process
places rtwtypes.h
in
slprj/
. Otherwise, the
software places target
/_sharedutilsrtwtypes.h
in
.model
_target
_rtw
Adding a model to a model hierarchy or changing an existing model in the hierarchy can
result in updates to the shared rtwtypes.h
file during code generation. If
updates occur, recompile and, depending on your development process, reverify previously
generated code. To minimize updates to the rtwtypes.h
file, make these
model configuration parameter changes:
Select model configuration parameter Support: complex numbers even if the model does not currently use complex data types. Selecting this parameter protects against a future requirement to add support for complex data types when integrating code.
Clear parameter Support non-inlined S-functions. If you use noninlined S-functions in the model, this option generates an error.
Avoid Duplicate Header Files for Exported Data
Exported header files appear in the shared utility folder when:
You control the file placement of declarations for signals, parameters, and states by defining and applying storage classes.
The code generator places utility code in a shared location.
For example, you can specify a header file for data by using:
A storage class that you define in the Embedded Coder Dictionary and map to categories of model data in the Code Mappings Editor – C.
The Code Generation tab in a Signal Properties dialog box.
The
HeaderFile
property of a data object. Data objects are objects of the classesSimulink.Signal
andSimulink.Parameter
.
If you want the declaration to appear in the file
, it is a best practice to leave the
header file name unspecified. By default, the code generator places data declarations in
model
.h
.model
.h
If you specify
as the header file
name, and if the code generator places utility code in a shared location, you cannot generate
code from the model. The code generator cannot create the file
model
.h
in both the model build folder and
the shared utility folder.model
.h
Reduce Shared Utility Code Generation with Incremental Builds
You can specify that the model build generates C source files in a shared utilities folder. See Control Placement of Shared Utility Code. These files include C source files that contain function definitions and header files that contain macro definitions. For this discussion, the term functions means functions and macros.
Blocks within the same model and blocks in different models can use a shared function when you use model reference or when you build multiple standalone models from the same start build folder. The code generator produces the code for a given function only once for the block that first triggers code generation. As the product determines the requirement to generate function code for subsequent blocks, it performs a file existence check. If the file exists, the model build does not regenerate the function. The shared utility code mechanism requires that a given function and file name represent the same functional behavior regardless of which block or model generates the function. To satisfy this requirement:
Model properties that determine function behavior contribute to the shared utility checksum or determine the function and file name.
Block properties that determine the function behavior also determine the function and file name.
During compilation, makefile rules for the shared utilities folder select compilation of
only new C files and incrementally archive the object file into the shared utility library,
rtwshared.lib
, or rtwshared.a
. Incremental compilation
also occurs.
Manage the Shared Utility Code Checksum
When you set the model configuration parameter Shared code placement
to Shared location
or when the model contains Model
blocks, the code generator places shared code in the shared utilities folder. The build
process generates a shared utilities checksum of the code generation configuration for the
shared code.
During subsequent code generation, if the checksum file
slprj/
exists relative to the current folder, the code generator reads that file. The code generator
verifies that the current model that you are building has configuration properties that match
the checksum of properties from the shared utility model. If mismatches occur between the
properties defined in target
/_sharedutils/checksummap.matchecksummap.mat
and the current model properties, you
see an error. Use the error message to manage the checksum (for example, diagnose and resolve
the configuration issues with the current model).
View the Shared Utility Checksum Hash Table
It is helpful to view the property values that contribute to the checksum. This example
uses the LctStartTermActions
model. To load the
checksum.mat
file into MATLAB®
and view the targetInfoStruct
that defines the checksum-related
properties:
Open the
LctStartTermActions
model. In the Command Window, type:openExample('LctStartTermActions')
Build the model, which is set up to produce shared utilities.
On the Apps tab, under Code Generation, click Simulink Coder.
On the C Code tab, in the Generate Code section, click the Build button.
Move to the
_sharedutils
folder created by the build process.cd slprj\grt\_sharedutils
Load the
checksummap.mat
file into MATLAB.load checksummap
Display the contents of
hashTbl.targetInfoStruct
and examine the checksum-related property values.hashTbl.targetInfoStruct
For this example, the Command Window displays
hashTbl.targetInfoStruct
for the shared utilities that you generated
from the model:
ans = struct with fields: ShiftRightIntArith: 'on' ProdShiftRightIntArith: 'on' Endianess: 'LittleEndian' ProdEndianess: 'LittleEndian' wordlengths: '8,16,32,32,64,32,64,64,64,64' Prodwordlengths: '8,16,32,32,64,32,64,64,64,64' TargetWordSize: '64' ProdWordSize: '64' TargetHWDeviceType: 'Custom Processor->Custom Processor' ProdHWDeviceType: 'Custom Processor->Custom Processor' TargetIntDivRoundTo: 'Zero' ProdIntDivRoundTo: 'Zero' UseDivisionForNetSlopeComputation: 'on' PurelyIntegerCode: 'off' PortableWordSizes: 'off' SupportNonInlinedSFcns: '' RTWReplacementTypes: '' MaxIdInt8: 'MAX_int8_T' MinIdInt8: 'MIN_int8_T' MaxIdUint8: 'MAX_uint8_T' MaxIdInt16: 'MAX_int16_T' MinIdInt16: 'MIN_int16_T' MaxIdUint16: 'MAX_uint16_T' MaxIdInt32: 'MAX_int32_T' MinIdInt32: 'MIN_int32_T' MaxIdUint32: 'MAX_uint32_T' MaxIdInt64: 'MAX_int64_T' MinIdInt64: 'MIN_int64_T' MaxIdUint64: 'MAX_uint64_T' BooleanTrueId: 'true' BooleanFalseId: 'false' TypeLimitIdReplacementHeaderFile: '' SharedCodeRepository: '' TargetLang: 'C' TargetLangStd: 'C89/C90 (ANSI)' InstructionSetExtions: 'None' PreserveExternInFcnDecls: 'on' ImplementImageWithCVMat: 'off' EnableSignedRightShifts: 'on' EnableSignedLeftShifts: 'on' TflName: 'None' TflCheckSum: [4.0787e+09 3.7630e+09 … ] (1×4 double) UtilMemSecPreStatement: '' UtilMemSecPostStatement: '' UtilMemSecComment: '' CodeCoverageChecksum: [3.6498e+09 78774415 … ] (1×4 double) TargetLargestAtomicInteger: 'Char' TargetLargestAtomicFloat: 'None' ProdLargestAtomicInteger: 'Char' ProdLargestAtomicFloat: 'None' LongLongMode: 'on' ProdLongLongMode: 'on' DataTypeReplacement: 'CoderTypedefs' ExistingSharedCodeUsingClassicNonFinite: 0 HeaderGuardPrefix: '' HardwareBoard: 'None' toolchainOrTMF: 'Microsoft Visual C++ 2022 v17.0 | nmake (64-bit Windows)'
Relate the Shared Utility Checksum to Configuration Parameters
Examine the targetInfoStruct
hash table from the shared utility
model. Some key-value pairs relate directly to a model property. Other pairs relate to
groups of properties.
The following table describes the key-value pairs.
Key Names | Model Properties |
---|---|
ShiftRightIntArith | TargetShiftRightIntArith |
ProdShiftRightIntArith | ProdShiftRightIntArith |
Endianess | TargetEndianess |
ProdEndianess | ProdEndianess |
wordlengths | TargetBitPerChar ,
TargetBitPerShort , TargetBitPerInt ,
TargetBitPerLong , TargetBitPerLongLong ,
TargetBitPerFloat ,
TargetBitPerDouble ,TargetWordSize ,
TargetBitPerPointer , TargetBitPerSizeT ,
TargetBitPerPtrDiffT |
Prodwordlengths | ProdBitPerChar ,
ProdBitPerShort , ProdBitPerInt ,
ProdBitPerLong , ProdBitPerLongLong ,
ProdBitPerFloat ,
ProdBitPerDouble ,ProdWordSize ,
ProdBitPerPointer , ProdBitPerSizeT ,
ProdBitPerPtrDiffT |
TargetWordSize | TargetWordSize |
ProdWordSize | ProdWordSize |
TargetHWDeviceType | TargetHWDeviceType |
ProdHWDeviceType | ProdHWDeviceType |
TargetIntDivRoundTo | TargetIntDivRoundTo |
ProdIntDivRoundTo | ProdIntDivRoundTo |
UseDivisionForNetSlopeComputation | UseDivisionForNetSlopeComputation |
PurelyIntegerCode | PurelyIntegerCode |
PortableWordSizes | PortableWordSizes |
SupportNonInlinedSFcns | SupportNonInlinedSFcns |
RTWReplacementTypes | EnableUserReplacementTypes,
ReplacementTypes |
MaxIdInt8 | MaxIdInt8 |
MinIdInt8 | MinIdInt8 |
MaxIdUint8 | MaxIdUint8 |
MaxIdInt16 | MaxIdInt16 |
MinIdInt16 | MinIdInt16 |
MaxIdUint16 | MaxIdUint16 |
MaxIdInt32 | MaxIdInt32 |
MinIdInt32 | MinIdInt32 |
MaxIdUint32 | MaxIdUint32 |
MaxIdInt64 | MaxIdInt64 |
MinIdInt64 | MinIdInt64 |
MaxIdUint64 | MaxIdUint64 |
BooleanTrueId | BooleanTrueId |
BooleanFalseId | BooleanFalseId |
TypeLimitIdReplacementHeaderFile | TypeLimitIdReplacementHeaderFile |
SharedCodeRepository | Reserved (internal use only) |
TargetLang | TargetLang |
TargetLangStd | TargetLangStandard |
InstructionSetExtions | InstructionSetExtensions |
PreserveExternInFcnDecls | PreserveExternInFcnDecls |
ImplementImageWithCVMat | ImplementImageWithCVMat |
EnableSignedRightShifts | EnableSignedRightShifts |
EnableSignedLeftShifts | EnableSignedLeftShifts |
TflName | CodeReplacementLibrary |
TflCheckSum | Reserved (internal use only) |
UtilMemSecPreStatement | MemSecFuncSharedUtil ,
MemSecPackage |
UtilMemSecPostStatement | MemSecFuncSharedUtil ,
MemSecPackage |
UtilMemSecComment | MemSecFuncSharedUtil ,
MemSecPackage |
CodeCoverageChecksum | Reserved (internal use only) |
TargetLargestAtomicInteger | TargetLargestAtomicInteger |
TargetLargestAtomicFloat | TargetLargestAtomicFloat |
ProdLargestAtomicInteger | ProdLargestAtomicInteger |
ProdLargestAtomicFloat | ProdLargestAtomicFloat |
LongLongMode | TargetLongLongMode |
ProdLongLongMode | ProdLongLongMode |
DataTypeReplacement | DataTypeReplacement |
ExistingSharedCodeUsingClassicNonFinite | Reserved (internal use only) |
HeaderGuardPrefix | HeaderGuardPrefix |
HardwareBoard | HardwareBoard |
toolchainOrTMF | Name of:
|
Generating Shared Utility Code for MATLAB Functions
The code generator does not produce shared utility code for either the main function or the subfunctions that you define inside a MATLAB Function block or a Stateflow® block.
If the block uses a MATLAB function that you define in a separate file, the code generator produces shared utility code for this function by default. However, if this function satisfies any of these conditions, the code generator marks the function as unshared and does not produce shared utility code:
Uses a
persistent
orglobal
variable.Calls a Simulink® function.
Is used in a block that has a function call output.
Refers to an input, output, or local variable of a Stateflow Chart (Stateflow).
Uses a bus or enumeration whose
DataScope
property is set to'Auto'
andHeaderFile
property is empty.Uses variable-size data.
Calls a custom C/C++ function using
coder.ceval
.Calls another MATLAB function that the code generator already marked as unshared for any of the reasons listed here. This rule applies transitively. For example, suppose that
foo1
callsfoo2
, which in turn callsfoo3
. Even if only the functionfoo3
uses aglobal
orpersistent
variable, the code generator marks all three functions as unshared.