Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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;
  MLINK ml = (MLINK)0;

  // Init and open
  env = MLInitialize((char*)0);
  int err = 0;
  char* argv[5];
  argv[0] = "ml";
  argv[1] = "-linkmode";
  argv[2] = "launch";
  argv[3] = "-linkname";
  argv[4] = "/usr/local/Mathematica/9.0/Executables/MathLink";
  *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
  envCloseLink(&ml);
  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;
  MLINK ml = (MLINK)0;

  // Init and open
  env = MLInitialize((char*)0);
  int err = 0;
  char* argv[5];
  argv[0] = "ml";
  argv[1] = "-linkmode";
  argv[2] = "launch";
  argv[3] = "-linkname";
  argv[4] = "/usr/local/Mathematica/9.0/Executables/MathLink";
  *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
  envCloseLink(&ml);
  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?

share|improve this question
add comment

2 Answers 2

up vote 6 down vote accepted

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.

share|improve this answer
add comment

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`\"]'"];

read[] := If[LinkReadyQ[kernel], LinkRead[kernel]];

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

LinkWrite[kernel, Unevaluated[CompilePrint::usage]]

read[]
(* ReturnPacket["CompilePrint[ cfun] prints a human readable form of a
compiled function."]
*)

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.

share|improve this answer
1  
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
    
@halirutan: Thanks a lot for your reply, yes it is a different approach, but you provided a really interesting point of view. Thanks a lot –  Andry May 14 '13 at 20:07
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.