When extending Mathematica through C or C++ code using the LibraryLink API, one common annoyance is that it’s not possible to see messages that the C code sends to stdout
or stderr
when using the graphical interface. While there are ways to send output directly to the active Mathematica notebook, often the C code is not written to be used exclusively with Mathematica and it simply prints debug messages to stderr
. Standard C assertion failures also cause messages to be printed to stderr
.
Here I will show how to view the Mathematica kernel’s output in a terminal window, even when using the graphical notebook interface.
On OS X, first we need to create a shell script which will launch the Mathematica kernel in a Terminal.app window. Put the following in a file named term_math
and edit the path to Mathematica’s location on the do script
line:
#!/bin/sh
# term_math
ARGS="$@"
osascript 2>&1>/dev/null <<EOF
tell application "Terminal"
do script ("'/Applications/Mathematica 10.app/Contents/MacOS/MathKernel' ${ARGS}; exit")
end tell
EOF
Open a terminal and make the script executable using the chmod a+x term_math
command.
Now we need to create a new kernel configuration: in Mathematica, choose Evaluation → Kernel Configuration Options…, then add a configuration as follows:
Be sure to use the correct and full path to the term_math
script. It will be different on your system than on mine.
On Windows systems the procedure is similar, but simpler: we don’t need to create a custom script, just use the math.exe
executable instead of math_term
in the kernel configuration. On Windows, Mathematica comes with two versions of the kernel executable: one that always runs in a visible command window, math.exe
, and one that is able to run without any visible windows, MathKernel.exe
.
To use this special kernel configuration, just set it as the active notebook’s kernel using Evaluation → Notebook’s Kernel → …
Finally, we need to make sure that any messages that the C code prints will be output immediately instead of staying buffered. After printing any output in C/C++ code, it is important to flush the output buffer, otherwise the messages may not show up in the terminal until the kernel quits. In C this can be done using fflush()
. When using C++ and <iostreams>
, it’s usually more convenient to simply use std::endl
to trigger flushing, for example std::cout << "some debug message" << std::endl;
. Alternatively, std::cout.flush();
works as well.
Here’s a quick way to test that everything works as it should:
Needs["CCompilerDriver`"]
src = "
#include \"WolframLibrary.h\"
#include <stdio.h>
DLLEXPORT mint WolframLibrary_getVersion(){ return WolframLibraryVersion; }
DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) { return 0; }
DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) { return; }
DLLEXPORT int message_test(WolframLibraryData libData, mint Argc, MArgument *Args, MArgument Res) {
printf(\"Test message\\n\");
fflush(stdout);
return LIBRARY_NO_ERROR;
}
";
lib = CreateLibrary[src, "MessageTest"]
messageTest = LibraryFunctionLoad[lib, "message_test", {}, "Void"]
messageTest[]
Evaluating this code with our special kernel configuration will produce the following:
I find this technique invaluable when writing LibraryLink code, especially when I need to keep it as independent from Mathematica as possible, or when using libraries that print their own debugging messages.
Comments !