C CODE GENERATOR TUTORIAL
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.
The code fragment is designed so that it could be compiled into a library; it includes generic initialization, life cycle 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.
The initial section of a generated C includes generic C initialization. A sample is shown below.
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.
Life Cycle Management
Generated C includes a section for managing the life cycle 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;
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 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)
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);
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 /SystemFiles/IncludeFiles/C.
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 /SystemFiles/Libraries/$SystemID.
|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 /SystemFiles/Libraries/$SystemID.
|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 /SystemFiles/Libraries/$SystemID.
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.
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.
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.
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.
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.
For your own code generation purposes you might wish to link your executable to one of the other runtime libraries.
You can generate C code for certain control expressions such as StateSpaceModel expressions.
The following makes an output directory to store the generated code.
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.
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.
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.