How do I incorporate my existing Fortran code into a Simulink model?

10 views (last 30 days)
I have existing Fortran code that I want to run as part of a Simulink model, and I do not want to have to rewrite the code to do so. Eventually, I want to compile the resulting model into a standalone executable.

Accepted Answer

MathWorks Support Team
MathWorks Support Team on 8 Aug 2011
Usually the easiest way to do this would be to make C wrappers for the Fortran components, and then integrate the calls the wrappers functions in whatever manner is most convenient (e.g. inside of S-function builder, or Stateflow, etc.).
There are three main steps to make it all work:
* Wrapping the Fortran code
* Integrating the code into Simulink
* Making the model generate the correct code for the final executable
Wrapping the Fortran code:
--------------------------
It is a good idea to first make a C wrapper for the code and make sure that it compiles, links, and runs on its own before integrating it with Simulink.
In general, the Fortran code will not have ".h" files for a C wrapper to "#include". Instead, it will be necessary to add "extern" declarations/prototypes for all of the Fortran functions and data to be used. However, something like "extern int my_fortran_function(int *argument)" likely will not work as written. This is because the Fortran compiler probably modifies the function names as it compiles them. As a result, it will be necessary to make the "extern" declaration match the function name waiting to be found in the Fortran object file. If the names in the C wrapper's "extern" declarations do not match the names for the Fortran variables and functions in the Fortran object file (not necessarily what appears in the Fortran source code), the code will compile, but the link will fail, most likely with "unresolved symbol" errors when linking the C wrapper's ".o" file.
There is a Linux tool called "readelf" which can read the entry points to object files. If you run "readelf -s fortran_object_file.o" from the command prompt, it will list all of the publicly-available symbols. These will be the names that you need to put into the "extern" declaration. You will also need to make the data types of the "extern" declaration be the equivalent of what Fortran uses. The type names most likely do not actually match, so you will need to sort out what the function argument data types end up being in C.
Also, Fortran passes arguments by reference by default, so the function calls end up being pointers instead of the listed data types. It is important to note that it implies that the Fortran code will be operating on its arguments and essentially writing to the data belonging to the caller.
Assuming that the Fortran object files do not need to be re-compiled all the time and that the C wrapper (which temporarily has a "main" in it), the compilation command would be something like
gcc my_c_wrapper.c fortran_file.o -o my_c_wrapper.out
(If you had more Fortran object files, you should be able to just add them, separated by spaces, to the list of contributing ".o" files.)
Integrating the code into Simulink
-----------------------------------
Once you have the above steps complete, it is necessary to remove the main() function that was in the wrapper. The next step is to use S-function builder, Stateflow, Embedded MATLAB, or the Legacy Code Tool to add a function call to the C wrapper function. In order to make the function prototype available to the block, you will need to add a "#include" statement for "my_c_wrapper.h" to the Configuration Parameters->Simulation Target->Custom Code->Header Files section.
With the header file included, use whichever of the block types listed above to add a call to the C wrapper function.
At this point, the block is still missing the source code that will need to be a part of any ".mex" file produced by those blocks. So add the object files to the Configuration Parameters->Simulation Target->Custom Code->Libraries section. (Even if you do not plan to actually simulate, this is still necessary because failure to produce a ".mex" file will prevent the tool from progressing during code-generation)
Making the model generate the correct code for the final executable
-------------------------------------------------------------------
Lastly, since you want to create a stand-alone executable, it is necessary to make the generated code work correctly as well. To do this, either duplicate the steps in "Integrating the code into Simulink" but use the "Configuration Parameters->Real-Time Workshop->Custom Code section" instead, or check the box indicating that the Simulation Target information should be applied to the generated code as well.
Caveats:
--------
Note that there are two big caveats with this approach: The first is that dependencies between the wrapper, the object files, and the Fortran files are NOT accurately represented in the makefile of the generated code. As a result, changes to this external code might not trigger a re-build in the way that you would expect. As a result, if there are changes to propagate from the external files, it is a good idea to recompile everything from scratch.
Secondly, all global variables in the external code are shared among all of the instances of blocks that use the external code. Thus, if one Stateflow block writes to a global variable in the Fortran code, that write will be immediately visible to all of the other blocks that read and write to it.

More Answers (0)

Categories

Find more on Simulink Coder in Help Center and File Exchange

Tags

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!