0

I wrote a C++ code which I am converting to a mex file so that I can run from Matlab. My original C++ code displays output of some function declared in third party library. However, when I convert it into mex file, the output seems to be suppressed.

NOTE: output of following command get suppressed

 int systemRet = std::system("./genb_test");

Original code:

 #include <stdio.h>  /* defines FILENAME_MAX */
 #include <cstdlib>

 #include <iostream>
 #ifdef _MSC_VER
    #include "direct.h" 
    #define GetCurrentDir _getcwd // window ??
 #else
    #include "unistd.h"
        #define GetCurrentDir getcwd
 #endif


int main()
{
  const char *ParentFolder = "/home/dkumar/libtsnnls-2.3.3/tsnnls/";

  int res3 = chdir(ParentFolder);
  if (res3  == -1){
    // The system method failed
    std::cout<< "the chdir method has failed \n"; 
  }    

  char cCurrentPath[FILENAME_MAX];
  if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
  {
      printf("Could not find current directory " );
      // return errno;
  }
  cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
  printf ("The current working directory is %s", cCurrentPath);
  printf ("\n");

  printf("Now running genb test " );
  int systemRet = std::system("./genb_test");
  if(systemRet == -1){
    // The system method failed
  }else{
    printf("System command execuated successfully " );
  }

return 0;
}

Output from original code:

The current working directory is /home/dkumar/libtsnnls-2.3.3/tsnnls
genb_tests

Creating 100 random test 121 x 89 problems using 
the genb algorithm of PJV. Each problem will be given 
to the tsnnls method, and the error printed below.
We require an error less than 1e-8 to pass the test.

#    M    N     Error         (PJV error)   (Spiv error)   Result 
----------------------------------------------------------------- 
  1  121  89    1.375271e-15  1.375271e-15  0.000000e+00  pass
  2  121  89    1.953126e-15  1.953126e-15  0.000000e+00  pass
  3  121  89    4.272569e-15  4.272569e-15  0.000000e+00  pass
  4  121  89    1.440234e-15  1.440234e-15  0.000000e+00  pass
  5  121  89    2.392671e-15  2.392671e-15  0.000000e+00  pass
 .......
 ....... 

 98  121  89    4.696796e-15  4.696796e-15  0.000000e+00  pass
 99  121  89    1.820247e-15  1.820247e-15  0.000000e+00  pass
100  121  89    1.520109e-15  1.520109e-15  0.000000e+00  pass

100 (of 100) tests passed.
Now running genb test System command execuated successfully

Translated original code to mex file: various input and output (LHS) are left as it is, since I would start using that soon.

#include <matrix.h> // mex
#include <mex.h>    // mex

#include <iostream>  // Basic I/O
using namespace std; // Basic I/O


/* Definitions to keep compatibility with earlier versions of ML */
#ifndef MWSIZE_MAX
typedef int mwSize;
typedef int mwIndex;
typedef int mwSignedIndex;

#if (defined(_LP64) || defined(_WIN64)) && !defined(MX_COMPAT_32)
/* Currently 2^48 based on hardware limitations */
# define MWSIZE_MAX    281474976710655UL
# define MWINDEX_MAX   281474976710655UL
# define MWSINDEX_MAX  281474976710655L
# define MWSINDEX_MIN -281474976710655L
#else
# define MWSIZE_MAX    2147483647UL
# define MWINDEX_MAX   2147483647UL
# define MWSINDEX_MAX  2147483647L
# define MWSINDEX_MIN -2147483647L
#endif
#define MWSIZE_MIN    0UL
#define MWINDEX_MIN   0UL
#endif

// 'Hello World!' program 
 #include <stdio.h>  /* defines FILENAME_MAX */
 #include <cstdlib>

 #include <iostream>
 #ifdef _MSC_VER
    #include "direct.h" 
    #define GetCurrentDir _getcwd // window ??
 #else
    #include "unistd.h"
        #define GetCurrentDir getcwd
 #endif


void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

  //const char *ParentFolder = "/home/dkumar/All_Matlab_Codes_DKU/";
  const char *ParentFolder = "/home/dkumar/libtsnnls-2.3.3/tsnnls/";


//declare variables
    mxArray *a_in_m, *b_in_m, *c_out_m, *d_out_m;
    const mwSize *dims;
    double *a, *b, *c, *d;
    int dimx, dimy, numdims;
    int i,j;

//associate inputs
    a_in_m = mxDuplicateArray(prhs[0]);
    b_in_m = mxDuplicateArray(prhs[1]);

//figure out dimensions
    dims = mxGetDimensions(prhs[0]);
    numdims = mxGetNumberOfDimensions(prhs[0]);
    dimy = (int)dims[0]; dimx = (int)dims[1];

//associate outputs
    c_out_m = plhs[0] = mxCreateDoubleMatrix(dimy,dimx,mxREAL);
    d_out_m = plhs[1] = mxCreateDoubleMatrix(dimy,dimx,mxREAL);

//associate pointers
    a = mxGetPr(a_in_m);
    b = mxGetPr(b_in_m);
    c = mxGetPr(c_out_m);
    d = mxGetPr(d_out_m);


  std::cout<< "Trying to change the directory "<< "\n";

  // COPIED FROM ORIGINAL C++ 
  int res3 = chdir(ParentFolder);
  if (res3  == -1){
    // The system method failed
    std::cout<< "the chdir method has failed \n"; 
  }

  char cCurrentPath[FILENAME_MAX];
  if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
  {
      printf("Could not find current directory " );
      // return errno;
  }
  cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
  printf ("The current working directory is %s", cCurrentPath);
  printf ("\n");

  printf("Now running genb test " );
  int systemRet = std::system("./genb_test");
  if(systemRet == -1){
    // The system method failed
  }else{
    printf("System command execuated successfully " );
  }

   // ADDED THIS PART at the suggestion of king_nak
   //Capturing the output terminal
    FILE * f = popen( "ls -al", "r" );
    if ( f == 0 ) {
        fprintf( stderr, "Could not execute\n" );
        return;
    }
    const int BUFSIZE = 1000;
    char buf[ BUFSIZE ];
    while( fgets( buf, BUFSIZE,  f ) ) {
        fprintf( stdout, "%s", buf  );
    }
    pclose( f );

    return;
}

The output is:

>> [c d]=test_snnls_mex(a,b)
Trying to change the directory 
The current working directory is /home/dkumar/libtsnnls-2.3.3/tsnnls
Now running genb test 
c =

     6     7     8
     9    10    11
    12    13    14


d =

     1     4     9
    16    25    36
    49    64    81

Some help would be appreciated.

Regards, Dushyant

Garima Singh
  • 1,410
  • 5
  • 22
  • 46

2 Answers2

1

Have you tried the mex-command mexPrintf ?

However, the output won't be printed before the whole mex-program has been executed. Two work-arounds for this are to either use

mexEvalString("disp('Bla')")

or

 mexPrintf("Bla")
 mexEvalString("drawnow;");
jolo
  • 423
  • 3
  • 10
  • Calling, either mexEvalString("./genb_test") or mexEvalString("system("./genb_test")") is giving me error. Could you please elaborate. – Garima Singh Jan 13 '15 at 10:19
  • Also my understanding is that mex file should replicate exactly what I have been doing in my C++ code. – Garima Singh Jan 13 '15 at 10:21
  • Try `mexEvalString("disp('...')")`. `mexEvalString` calls a matlab function inside your mex-program - and "./genb_test" isn't a matlab-function. – jolo Jan 13 '15 at 10:22
  • thanks for clarifying. ./genb_test is gcc executable. This means that your solution would not be valid for this case. – Garima Singh Jan 13 '15 at 10:29
1

std::system will start the system's command processor to execute the command. If you have a console app, this will print the output to the current console. This is why you see it in your test program. The output is not passed to the calling program!

In your case, Matlab seems to start the process in the background, where the output is discarded. Try instead opening the process and reading out its output into your program/MEX.

In POSIX, you can use popen (see for example this answer), in Windows you can use ReadPipe (cf. this article)

UPDATE
You have to adjust the code I have linked to. The original code calls ls -al and prints its output to the screen. You have to call your process genb_test!

Use this code to get the output in matlab, instead of your std::system call:

FILE * f = popen( "genb_test", "r" );  // <- call genb_test
if ( f == 0 ) {
    fprintf( stderr, "Could not execute\n" );
    return;
}
const int BUFSIZE = 1000;
char buf[ BUFSIZE ];
while( fgets( buf, BUFSIZE,  f ) ) {
    mexPrintf(buf); // <- use mexPrintf to print to matlab
}
pclose( f );
Community
  • 1
  • 1
king_nak
  • 11,313
  • 33
  • 58
  • thanks. I could see output at terminal where I started the matlab from. I also tried using popen (please see my modified code) and it also seems to be sending output to terminal OR, I may not be using properly. However, I would like to capture the output of command using system: c = run_some_test(inputs...); In other words, I would like the value of c to be available in mex file. Please help. – Garima Singh Jan 13 '15 at 11:16
  • I extended the answer with an example. You have to call your process, not `ls -al`! – king_nak Jan 13 '15 at 15:42