Contenuto principale

Register Custom Toolchain and Build Executable

A toolchain is a collection of tools required to compile and link code for a specified platform. The tools can include compilers, linkers, and archivers. You can configure the tools in a toolchain with multiple options, and group tool specifications into types of configurations.

This example shows how to create, register, and use a toolchain to build an executable file using the Intel® compiler for 64-bit Windows® with the Microsoft® compatible compiler driver. The Intel compiler uses syntax that is compatible with Microsoft Visual Studio tools, and it builds the executable for a 64-bit Windows target machine. However, the concepts and programming interface demonstrated in the example apply for all toolchains, including those that cross-compile for target hardware.

Prerequisites and Limitations:

  • This example can only be run on a Windows machine.

  • To run the example, you need to have Microsoft Visual Studio installed.

  • To run the example, you need to have Intel OneAPI installed in its default location.

Open Model

Open the CounterModel model.

modelName = "CounterModel";
open_system(modelName)

Model CounterModel.

Create Toolchain Object

Create a target.Toolchain object with definitions suitable for an Intel compiler on a 64-bit Windows platform, and add it to the internal database so that it can be used by your model.

Retrieve from the internal database all the target.Processor objects compatible with Intel compiler on a 64-bit Windows platform. Store the retrieved array in the variable processorObjs.

processorObjs = [target.get("Processor",Name="x86-64 (Windows64)"), ...
                 target.get("Processor","Custom Processor-MATLAB Host Computer")];

Create a skeleton toolchain object using the necessary name-value arguments.

toolChainObj = target.create("Toolchain", ...
  Name="Intel OneAPI - using Microsoft Compatible Compiler Driver", ...
  MakeToolType="NMake", ...
  MakeTool="nmake", ...  
  HardwareSupport=processorObjs, ... % Previously created object array.
  CCompiler="icx", ...
  CppCompiler="icx -EHs", ...
  Linker="link", ...
  CppLinker="link", ...
  CompilerFlags="-nologo", ...
  LinkerFlags="-nologo", ...
  Archiver="lib -nologo", ...
  ObjectExtension=".obj", ...
  ExecutableExtension=".exe", ...
  SharedLibraryExtension=".dll", ...
  StaticLibraryExtension=".lib", ...
  CommandFile="@");

Use the CCompiler, CppCompiler, Linker, and CppLinker arguments to specify C and C++ compilers and linkers in the toolchain. In the value for CppCompiler, note the flag -EHs, which is only used by the C++ the compiler. The specified CompilerFlags and LinkerFlags are common flags, used for both C and C++ compilers and linkers.

For the HardwareSupport argument, use the target.Processor object array, previously retrieved from the internal database.

These arguments specify extensions for derived files generated by the toolchain tools:

  • ObjectExtension=".obj"

  • ExecutableExtension=".exe"

  • SharedLibraryExtension=".dll"

  • StaticLibraryExtension=".lib"

Compilers, linkers, and archivers can read multiple command-line flags from a text file, instead of directly from the command line, helping the build process avoid exceeding the command-line maximum length limitation. Enable this feature with the CommandFile argument. The build process prefixes the text file name with @.

Set preprocessor definitions to be used, by default, when building code with this toolchain. Specifically, in the example, specify the definition that disables some compiler warnings about using ANSI C functions for which newer alternatives are available.

toolChainObj.BuildRequirements.Defines = "-D_CRT_SECURE_NO_WARNINGS";

Create a target.Command object to specify a batch file to use for setting up the environment for the toolchain.

When the full path of the batch file contains no white spaces, you can use this format to create the object:

target.create("Command","fullPath")

Here, fullPath is the full path of the batch file. When the full path contains white spaces, use the String property to prevent the spaces from being interpreted as separators between the command and arguments. For the example, use this:

setupCMD = target.create("Command", ...
                          String="C:\Program Files (x86)\Intel\oneAPI\setvars.bat");
toolChainObj.EnvironmentConfiguration.SetupCommand = setupCMD;

Each directive specifies the command line flag to use with the tool (compiler or linker) for controling a specific behavior of the tool. For example, the value of the Debug directive specifies the command line flag that enables debug symbol generation when passed to the compiler. Specifically, compilers in this toolchain enable debug symbol generation when the flag "-Zi" is passed in the command line. So you specify the Debug directive as "-Zi".

Iterate over the compilers in the toolchain, and for each specify the required directives.

tcCompilers = [toolChainObj.getBuildToolOfType("C Compiler"), ...
               toolChainObj.getBuildToolOfType("C++ Compiler")];

for curCompiler = tcCompilers
  curCompiler.setDirective(CompileFlag="-c")
  curCompiler.setDirective(Debug="-Zi")
  curCompiler.setDirective(DisableOptimization="/Od")
  curCompiler.setDirective(EnableOptimization="/O2")
  curCompiler.setDirective(IncludeSearchPath="-I")
  curCompiler.setDirective(OutputFlag="-Fo")
  curCompiler.setDirective(PreprocessFile="-E")
  curCompiler.setDirective(PreprocessorDefine="-D")
end

Iterate over the linkers in the toolchain, and for each specify the required directives.

tcLinkers = [toolChainObj.getBuildToolOfType("Linker"), ...
             toolChainObj.getBuildToolOfType("C++ Linker")];

for curLinker = tcLinkers
  curLinker.setDirective(Library="")
  curLinker.setDirective(LibrarySearchPath="-L")
  curLinker.setDirective(OutputFlag="-out:")
  curLinker.setDirective(Debug="")
  curLinker.setDirective(Shared="-dll")
  curLinker.setDirective(DefFile="-def:")
end

The last directive in the loop, DefFile, is necessary when you configure the Simulink® Coder™ to build a shared library from your model instead of an executable file. In this case, the directive DefFile is used to include a module definition file with information about the exported variable and function symbols. To have the Simulink Coder build a shared library, use one of these methods:

  • Before building your model, specify its system target file as ert_shrlib.tlc.

  • Use the slbuild function to build your model, and specify the build output type as SharedLibrary:

slbuild(modelName,BuildOutputType="SharedLibrary")

Specify the OutputFlag directive to indicate the prefix of the static library to be created by the archiver of the toolchain.

tcArchiver = toolChainObj.getBuildToolOfType("Archiver");
tcArchiver.setDirective(OutputFlag="-out:")

Add Toolchain Object to Internal Database

Use the target.add function to add the toolchain and associated objects to the internal database. Store the added in the variable addedObjects so that you can remove them later from the database.

addedObjects = target.add(toolChainObj,SuppressOutput=true);

Use Toolchain Object

To use the newly created toolchain object, configure the model to use the hardware specifications of the toolchain object, and then specify it as the toolchain for the model to use:

1. Open the Configuration Parameters dialog box of the model.

2. On the left pane, navigate to Hardware Implementation.

3. On the right pane, from the Device vendor list, select Intel.

4. The parameter Device type becomes available. From its drop-down list, select x86-64 (Windows64).

5. Under Advanced parameters, make sure that Test hardware is the same as production hardware is selected. When this parameter is selected, the list of available toolchains is determined by the values of the Device vendor and Device type parameters (which you just specified).

Configuration Parameters dialog box. The parameter Device vendor is specified as Intel. The parameter Device type is specified as x86-64 (Windows64). The parameter Test hardware is the same as production hardware is selected.

6. On the left pane, navigate to Code Generation.

7. From the Toolchain list, select the newly created toolchain, Intel OneAPI - using Microsoft Compatible Driver.

8. Click Apply.

Configuration Parameters dialog box. The parameter Toolchain vendor is specified as Intel OneAPI - using Microsoft Compatible Driver.

Alternatively, configure the parameters programmatically by entering these commands in the Command Window:

set_param(modelName,ProdHWDeviceType="Intel->x86-64 (Windows64)")
set_param(modelName,Toolchain=toolChainObj.Name)

Build Model with Custom Toolchain

Now build the model with the new custom toolchain.

If you do not have Microsoft Visual Studio or Intel OneAPI installed, enter this command in the Command Window to only generate code without building the executable.

set_param(modelName,GenCodeOnly="on")

Use the function slbuild in the Command Window to build the model (or just generate code if you configured it to only generate code).

slbuild(modelName)
### Searching for referenced models in model 'CounterModel'.
### Total of 1 models to build.
### Starting build procedure for: CounterModel
### Successful completion of code generation for: CounterModel

Build Summary

Top model targets:

Model         Build Reason                                         Status           Build Duration
==================================================================================================
CounterModel  Information cache folder or artifacts were missing.  Code generated.  0h 0m 52.46s

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

If you built the model, use the system function in the Command Window to run the generated executable:

system(modelName);

Remove Added Objects from Database

To remove the objects you added to the internal database, use the target.remove function.

target.remove(addedObjects,SuppressOutput=true)