The generation of the executable can be done within Mathematica or outside Mathematica. The Mathematica 8.0 help for my Linux Fedora 64bits requires a minor adjustment in order to work. For Linux systems:
"Libraries" -> "WolframRTL_Static_Minimal.lib"
must be replaced by
"Libraries" -> "WolframRTL_Static_Minimal"
(Thanks to Abdul Dakkak for helping on this)
How do we compile the generated code outside Mathematica? This issue is detailed next
- The Mathematica code that generates the C code for a simple example taken from the help is
code = CProgram[ CInclude["stdio.h"], CInclude["compute.h"], CFunction["int", "main", {{"int", "argc"}, {"char", CDereference[CArray["arg", {}]]}}, CBlock[{ CDeclare["double", CAssign["num1", 20.4]], CDeclare["double", "num2"], CDeclare["WolframLibraryData", CAssign["libData", CCall["WolframLibraryData_new", {"WolframLibraryVersion"}]]], CCall["Initialize_compute", {"libData"}], CCall["compute", {"libData", "num1", CAddress["num2"]}], CCall["printf", {CString["%5.2f\n"], "num2"}], CCall["WolframLibraryData_free", {"libData"}], CReturn[0]}]] ]; cStr = ToCCodeString[code] mainSource = Export[FileNameJoin[{outDir, "main.c"}], cStr, "Text"] c = Compile[{{x}}, x^2]; CCodeGenerate[c, "compute", FileNameJoin[{outDir, "compute.c"}], "CodeTarget" -> "WolframRTL"]; CCodeGenerate[c, "compute", FileNameJoin[{outDir, "compute.h"}], "CodeTarget" -> "WolframRTLHeader"];
where
outDirmust be defined according the user's desires
- The generated main.c file with a minor manual retouching in the printf function is
#include "compute.h" #include "WolframRTL.h" int main(int argc, char *arg[]) { double num1 = 20.4; double num2; WolframLibraryData libData = WolframLibraryData_new(WolframLibraryVersion); Initialize_compute(libData); compute(libData, num1, &num2); printf("%5.2f\n", num2); WolframLibraryData_free(libData); return 0; }
- The generated file compute.c is
#include "math.h" #include "WolframRTL.h" static WolframCompileLibrary_Functions funStructCompile; static mbool initialize = 1; #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; } } DLLEXPORT int compute(WolframLibraryData libData, mreal A1, mreal *Res) { mreal R0_0; mreal R0_1; R0_0 = A1; R0_1 = R0_0 * R0_0; *Res = R0_1; funStructCompile->WolframLibraryData_cleanUp(libData, 1); return 0; }
- The generated file compute .h is
#include "WolframLibrary.h" EXTERN_C DLLEXPORT int Initialize_compute(WolframLibraryData libData); EXTERN_C DLLEXPORT void Uninitialize_compute(WolframLibraryData libData); EXTERN_C DLLEXPORT int compute(WolframLibraryData libData, mreal A1, mreal *Res);
- Finally, the Makefile that takes care of the compilation is
CXX = /usr/bin/c++ MATHEMATICA_INCLUDE_PATH = /usr/local/Wolfram/Mathematica/8.0/SystemFiles/IncludeFiles/C MATHEMATICA_LIB_PATH = /usr/local/Wolfram/Mathematica/8.0/SystemFiles/Libraries/Linux-x86-64 a.out: main.c compute.o ${CXX} -I${MATHEMATICA_INCLUDE_PATH} -L${MATHEMATICA_LIB_PATH} -lm -lWolframRTL -lmkl_intel_lp64 -lmkl_intel_thread -lmkl_core -liomp5 -pthread compute.o main.c compute.o: compute.c ${CXX} -c -I${MATHEMATICA_INCLUDE_PATH} -L${MATHEMATICA_LIB_PATH} compute.c
Of course, make sure that the libraries are in the right place and eventually you will need to add the path of the Mathematica libraries in ld.so.conf and apply /sbin/ldconfig
- A more elaborated example taking a real matrix input and a real matrix output is here
- A similar example implemented for complex matrices here