I am using MathLink with C/C++ on a Unix system in order to call a Mathematica (version 9) function and get the result.

The function I need to call is a personal function of mine MyFunct[x,y,z]. The function takes three arguments and will return a Real. This function is defined in myscript.m file at this path: /home/myuser/Documents/mym/myscript.m.

I have the following C code:

#include <mathlink.h>
#include <stdio.h>

int main(int argc, char** argv) {

MLENV env = (MLENV)0;

// Init and open
env = MLInitialize((char*)0);
int err = 0;
char* argv[5];
argv[0] = "ml";
argv[2] = "launch";
*link = MLOpenArgcArgv(*env, 5, argv, &err);

fprintf(stdout, "All ok!\n");

// Putting function
MLPutFunction(ml, "N", 1);
MLPutFunction(ml, "Cos", 1);
MLPutInteger(ml, 2);
MLEndPacket(ml);
MLFlush(ml);

// Getting
int pkt;
while ((pkt = MLNextPacket(ml),pkt) && pkt != RETURNPKT) {
MLNewPacket(ml);
if (MLError(ml)) fprintf(stdout, "Error!\n");
}
double r = 0;
MLGetReal(ml, &r);
fprintf(stdout, "Got %f!\n", r);

// Close and deinit
fprintf(stdout, "Closed!\n");
envDeInitEnv(&env);
fprintf(stdout, "Deinitialized!\n");

fprintf(stdout, "Over!\n");
}


The above code works! Now consider the following:

int main(int argc, char** argv) {

MLENV env = (MLENV)0;

// Init and open
env = MLInitialize((char*)0);
int err = 0;
char* argv[5];
argv[0] = "ml";
argv[2] = "launch";
*link = MLOpenArgcArgv(*env, 5, argv, &err);

fprintf(stdout, "All ok!\n");

// CALLING 'GET' ////////////////////////////////////////////////////////
fprintf(stdout, "Putting [GET]...\n");
if (!MLPutFunction(ml, "Get", 1)) fprintf(stdout, "Err!\n");;
if (!MLPutString(ml, "/home/myuser/Documents/mym/myscript.m")) fprintf(stdout, "Err!\n");
MLEndPacket(ml);
if (!MLFlush(ml)) fprintf(stdout, "Err!\n");
int pkt = 0;
while ((pkt = MLNextPacket(ml),pkt) && pkt != RETURNPKT) {
MLNewPacket(ml);
if (MLError(ml)) fprintf(stdout, "Error!\n");
}
// END //////////////////////////////////////////////////////////////////

// CALLING FUNCT ////////////////////////////////////////////////////////
fprintf(stdout, "Calling impulse...\n");
MLPutFunction(ml, "MyFunct", 3);
MLPutInteger(ml, 1);
MLPutInteger(ml, 4);
MLPutInteger(ml, 2);
MLEndPacket(ml);
MLFlush(ml);
int pkt2 = 0;
while ((pkt2 = MLNextPacket(ml),pkt2) && pkt2 != RETURNPKT) {
MLNewPacket(ml);
if (MLError(ml)) fprintf(stdout, "Error!\n");
}
double r = 0;
if (!MLGetReal(ml, &r)) fprintf(stdout, "Error in getting!\n"); // LINE REF1
fprintf(stdout, "Got %f\n", r);
// END //////////////////////////////////////////////////////////////////

// Close and deinit
fprintf(stdout, "Closed!\n");
envDeInitEnv(&env);
fprintf(stdout, "Deinitialized!\n");

fprintf(stdout, "Over!\n");
}


I got an error in LINE REF1. I understood that the problem is the CALLING 'GET' block. If I delete this block and call a Mathematica built in function (like in the previous code), I get no errors. But if I insert the block CALLING 'GET' and then try to call one of the functions defined in my external file or a built in Mathematica function, errors are raised at the specified line (LINE REF1).

Maybe I've made a mistake when trying to perform two sequential operations on the link... How do I solve this?

-

After you call Get, you run a packet loop, waiting for the ReturnPacket. But you never read or discard the contents of that ReturnPacket. That means that the whatever expression that Get returns (it will be the result of last evaluation in the myscript.m file, perhaps the symbol Null) is still waiting on the link. Then you call your function and wait for the result with the pkt2 loop. But the first call to MLNextPacket() in that loop will return 0 because it is a MathLink error to call MLNextPacket() when data from a previous packet is still waiting. If you move your MLError() call in that while loop to after the loop (where it belongs), you would see that an error condition has already occurred, before the call to MLGetReal().

The fix is simple: a call to MLNewPacket() after your packet loop for the Get call (line 30), to throw away the contents of the first ReturnPacket.

-

Forgive me my ignorance to not try your sample code and instead give you an idea for a completely different approach. Since you are just launching a MathKernel in your MathLink program, why don't you use the -run option, to load your package during the launch?

You can test this directly in the front end

kernel = LinkLaunch[
First[\$CommandLine] <>
" -mathlink -run 'Get[\"CompiledFunctionTools\"]'"];

(* InputNamePacket["In[1]:= "] *)


As you see the CompiledFunctionTools package was successfully loaded. Therefore, the only thing you have to do is to include this in your argv and you should be done.
Or why not drive the whole C program from Mathematica and use MLEvaluate` for callbacks? It may simplify things further. –  Szabolcs May 13 '13 at 22:49