Code Generation
Code generation from
Mathematica involves converting programs written in the
Mathematica language into other languages and then supporting them so that they can be executed. The
Mathematica compiler provides a system for code generation into the C language.
The CCodeGenerator Package
The CCodeGenerator package is a key component of code generation from
Mathematica. It provides a number of functions, which are described below, that make use of the
Mathematica compiler for generating C code.
| CCodeGenerate[comp,fun,file] | generates C code for compiled function comp, using function fun, and saves in file |
| CCodeStringGenerate[comp,fun] | generates a string of C code for compiled function comp, using function fun |
| SymbolicCGenerate[comp,fun] | generates SymbolicC for compiled function comp, using function fun |
| LibraryGenerate[comp,fun] | generates a shared library for compiled function comp, using function fun. |
Functions provided by the CCodeGenerator package.
To use the CCodeGenerator package you have to load it.
This is a compiled function to use to demonstrate code generation.
The following generates a fragment of C code for the compiled function.
| Out[3]= |  |
The code fragment is designed so that it could be compiled into a library; it includes generic initialization, lifecycle management for this function, and the actual body of the function.
An application can call this function by importing a header file and linking against a suitable code module such as a shared library. You can also generate the header by setting the

option to

as shown below.
| Out[4]= |  |
Generic Initialization
The initial section of a generated C includes generic C initialization. A sample is shown below.
#include "math.h"
#include "WolframRTL.h"
static WolframCompileLibrary_Functions funStructCompile;
static mbool initialize = 1;
WolframRTL.h is a header file that sets up various important definitions.
WolframCompileLibrary_Functions is a type that holds a collection of callback functions; it is an immutable object that holds no state. An instance of this,
funStructCompile, is kept in the file.
initialize is an mbool variable, which is used by the specific initialization functions.
Lifecycle Management
Generated C includes a section for managing the lifecycle of the code. This involves initialization and uninitialization specific to the particular function. A sample is shown below.
# include "compute.h"
DLLEXPORT int Initialize_compute (WolframLibraryData libData)
{
if ( initialize)
{
funStructCompile = libData -> compileLibraryFunctions;
initialize = 0;
}
return 0;
}
DLLEXPORT void Uninitialize_compute (WolframLibraryData libData)
{
if ( ! initialize)
{
initialize = 1;
}
}
This includes the header file, generated by setting

option to

; it also includes a function to initialize the structures,
Initialize_compute, and one to uninitialize any state,
Uninitialize_compute. The initialization function must be called before the main function is used.
The initialize and the uninitialize functions must be called with a
WolframLibraryData argument. This can be created by the loading function.
The Function
The actual body of a function is shown below. Note that the name "compute" was set in the call to
GenerateCCodeString.
DLLEXPORT int compute (WolframLibraryData libData, mreal A1, mreal *Res)
{
mreal R0_0;
mreal R0_1;
mreal R0_2;
mreal R0_3;
R0_0 = A1;
R0_1 = R0_0 * R0_0;
R0_2 = sin (R0_1);
R0_3 = R0_1 + R0_2;
*Res = R0_3;
funStructCompile -> WolframLibraryData_cleanUp (libData, 1);
return 0;
}
This shows how the function arguments take the input and also the result as a pointer. The actual return value is used to indicate an error. The function is declared with
DLLEXPORT, a macro defined in
WolframLibrary.h. This allows the function to be exported from a Windows DLL; on non-Windows platforms the macro has an empty definition.
The function also needs a
WolframLibraryData argument. This can be created by the loading function.
Working with Generated Code
Code generated by
Mathematica needs various support files, which are included in the
Mathematica layout. This includes header files that contain declarations for building and libraries that contain the actual code needed to support generated functions.
| WolframRTL.h | header file for the Wolfram Runtime Library definitions |
Header file used by generated code, found in
.
There are various runtime libraries to support the generated code for each platform.
| WolframRTL.dll | full shared library for runtime support |
| WolframRTL.lib | exports for full shared library for runtime support |
| WolframRTL_Minimal.dll | minimal shared library for runtime support |
| WolframRTL_Minimal.lib | exports for minimal shared library for runtime support |
| WolframRTL_Static_Minimal.lib | minimal static library for runtime support |
Runtime library support for generated code on Windows platforms, found in
.
| libWolframRTL.so | full shared library for runtime support |
| libWolframRTL_Minimal.so | minimal shared library for runtime support |
| libWolframRTL_Static_Minimal.a | minimal static library for runtime support |
Runtime library support for generated code on Linux platforms, found in
.
| libWolframRTL.dylib | full shared library for runtime support |
| libWolframRTL_Minimal.dylib | minimal shared library for runtime support |
| libWolframRTL_Static_Minimal.a | minimal static library for runtime support |
Runtime library support for generated code on Macintosh platforms, found in
.
The full runtime libraries all have a dependency on other libraries such as the Intel MKL library, which is bundled with
Mathematica. This gives very fast execution speed, but it means that to use the library externally from
Mathematica you have to arrange to use the MKL library.
The minimal libraries have fewer dependencies on other libraries. For example, they have no dependency on the Intel MKL library. This gives slower execution speed for computations that need to use MKL, such as matrix multiplications.
You can compile generated files using whatever tools you like. The documentation here will show how to use the
Mathematica C Compiler Driver package. First, you have to load the packages.
This creates a temporary directory to hold files and the resulting executable.
| Out[4]= |  |
This is some sample C code to test the generated code; it is written using
SymbolicC. It calls a function
compute passing in an argument and receives the result, which is then printed in output.
| Out[6]= |  |
Notice how the calling function creates a
WolframLibraryData object; this is used for the call to the
initialize function and also in the call to the
compute function.
The following writes the C code to an output file.
| Out[7]= |  |
Here, a compiled function is created, which is then used to generate a C file and a header file. All the output goes into the output directory created earlier.
This compiles all the source files into an executable. Notice how it links in the static minimal library; this is an easy way to set up this demonstration. On a different platform you would need to use the appropriate library.
| Out[11]= |  |
You can run the generated code in a shell; it will run the computation that started in the compiled function and print out the result.
You can also run the generated code from
Mathematica, using
Import to read the result.
| Out[12]= |  |
For your own code generation purposes you might wish to link your executable to one of the other runtime libraries.
Control Expressions
You can generate C code for certain control expressions such as
StateSpaceModel expressions.
| Out[1]= |  |
The following makes an output directory to store the generated code.
| Out[2]= |  |
Here, C code for the state space model is generated and stored in the file
control.c.
A header file was created as well as a C file.
| Out[5]= |  |
You can compile this C code in an executable or a library with the
CCompilerDriver package. First, it has to be loaded.
This creates a library for the control expression.
| Out[7]= |  |
The library can then be used in computations external to
Mathematica.
Scope of Generated Code
This section describes the scope of
Mathematica computations that can be used with the code generator.
The code generator is based on the
Mathematica compiler. You must be using
Compile in order to make any progress with the code generator.
However, not all inputs processed by the compiler can be turned into generated code. This includes any
external calls, which call back to
Mathematica. These cannot be used for code generation.