Main Content

Importing and Testing Custom C/C++ Code

You can test custom C or C++ code by importing it into Simulink® using the Code Importer wizard in the Test Manager or API commands at the MATLAB® command line. You can perform unit testing to test a subset of your C code or integration testing to test your complete C or C++ code. When you import your code, the code importer:

  • Converts the C code functions to Simulink C Caller blocks and saves those blocks in a Simulink library

  • Creates an internal harness for each Simulink C Caller block

  • Generates a test file

For unit tests, the code importer additionally creates a sandbox to isolate the imported functions.

Import Code Using the Wizard or the API

To import and test custom C or C++ code using the Code Importer wizard, open the Test Manager and select New > Test for C/C++ Code. The wizard steps are shown in the Conduct Unit Testing on Imported Custom Code by Using the Wizard example. After you import the code using the wizard, the Test Browser pane of the Test Manager shows the generated test file, test suites, and test cases, and automatically fills the library model and test harness fields and coverage settings for each test case. You can customize the test cases in the Test Manager by adding inputs, assessments, links to requirements, or other options.

The Import Custom Code for Unit Testing Using API Commands example shows the classes and methods for importing code. The code importer sets the property values for the generated library, test file, test suites, test cases, and coverage. You can customize the test cases by using API commands to add inputs, assessments, links to requirements, or other options.

Before you run the test cases, either change the current folder to the folder that contains the generated artifacts or add the generated data dictionary to the path. Then run the test cases and view the coverage and other test results.

Code Importer Generated Artifacts

The code importer creates these artifacts:

  • A Simulink library with C Caller blocks for each imported custom code function.

  • An internal test harness for each C Caller block. For each generated harness, the solver is FixedStepDiscrete, and coverage is enabled.

  • An MLDATX test file. The test file includes a test suite and test case for each C Caller block. The code importer also sets these coverage types:

    • Decision coverage

    • Condition coverage

    • MCDC coverage

    • Lookup table coverage

    • Signal range coverage

    • Coverage for Simulink Design Verifier blocks

    • Relational boundary coverage

    • Signal range coverage

  • Simulink data dictionary

Additionally, for unit tests only, the code importer creates:

  • A sandbox to isolate the functions being tested

  • Stubs, if any source files have undefined symbols

Limitations and Workarounds

These limitations and workarounds apply to using the custom C or C++ Code Importer.

General Limitations and Workarounds

  • For integration tests, if your code includes C++ functions, add wrappers around them to make them C-compatible before importing the functions into Simulink.

  • These C types, and functions with formal arguments that use these types, cannot be imported. Global variables that use these types are not exposed as ports on the C Caller block:

    • Structures with unions or pointer members

    • Functions with inputs that have more than one level of pointer indirection (for example, >=**)

    • Functions that return a pointer

    • Types with names longer than 63 characters, and functions and variables that use those types

  • If your code has many global variables, use a Stateflow® chart instead of an Initialize Function block to set the variables to their initial values in your Simulink model.

  • If a header file or C or C++ file contains assembly code that is defined in the function body, the code importer does not import that function. This limitation applies only if the assembly code is not compatible with the host computer. To import the function,

    • For integration tests, replace the assembly code by using an #ifdef directive.

    • For unit tests, the function is moved automatically to the auto_stub.c file with an empty body. To import the function into Simulink, manually stub the function in man_stub.c.

  • For target-specific code, if the code accesses absolute memory addresses, comment out that code to prevent the simulation from failing.

Header Files

  • If the same header file is included multiple times and each inclusion is preceded by a different preprocessor directive (such as, #define X 1, #define X 2), the code might not import correctly.

  • If assembly code is defined in the header file, define a compatible macro by using an #ifdef directive. For example, if your code is:

    #define XYZ(K,L) {\
    asm("MOVLW " ___mkstr(K) ); \
    asm("MOVLW " ___mkstr(L) ); \
    }
    
    replace it with:
    #ifndef IS_SL_IMPORT
    #define XYZ(K,L)  {\
    asm("MOVLW " ___mkstr(K) ); \
    asm("MOVLW " ___mkstr(L) ); \
    }
    #else
    // a valid implementation
    #endif
    
    Then, add IS_SL_IMPORT to the list of defines when you import code.

Unit Tests

These limitations and workarounds apply only to unit tests.

  • Only C code is supported for importing.

  • If a source or header file contains a function definition that is included multiple times in the source file being imported, update the code so the function definition appears only once.

  • All included files, using #include, should be self-contained, that is, they compile on their own. Specifically, a header should have header guard and include all other headers that it needs.

See Also

| |

Related Topics