1
$\begingroup$

The task is to compile, link and install in Mathematica (9.0, Linux 64 bit) some functions defined in C++. These functions are defined within classes. I have access to the header which forward define the classes, but I would like not to touch the C++ code that properly defines what these functions do.

$\endgroup$
3
$\begingroup$

First approach is to create C wrappers for the C++ code. The very simple example I work below defines a class "bola" which represents a sphere with a radius. The member function gives the surface. So, the forward definition (C++ style) of the class functions is in "bola.h" and the definitions of the functions are in "bola.cpp". I give the code for these two at the end. We could assume that these two files have been compiled before and maybe we only have access to the compiled object.

The wrapper header:

// (*This file is bola_cWrap.h*)
#ifndef BOLA_H
#define BOLA_H
#ifdef __cplusplus
extern "C" {
#endif

typedef struct bola bola;

bola* newBola();
void bola_setRadius(bola* b, double radius);
double bola_getSurface(bola* b);
void deleteBola(bola* b);

#ifdef __cplusplus
}
#endif
#endif

And the definitions of these wrap functions :

// (*This file is bola_cWrap.cpp*)
#include "bola.h"
#include "bola_cWrap.h"
extern "C" {
  bola* newBola(){return new bola();}
  void bola_setRadius(bola* b, double radius){b->setRadius(radius);}
  double bola_getSurface(bola* b){return(b->getSurface());}
  void deleteBola(bola* b){delete b;}

}

The template of the link between Mathematica and the 'surface' function:

::  // (*This is surfaceBolaM.tm*)
void surfaceBolaM P(( double x));

:Begin:
:Function:       surfaceBolaM
:Pattern:        surfaceBolaM[x_Real]
:Arguments:      { x }
:ArgumentTypes:  { Real}
:ReturnType:     Manual
:End:

And the C function:

// (*This file is surfaceBolaM.c *)
#include "mathlink.h"
#include "bola_cWrap.h"

 void surfaceBolaM(double r);
 void surfaceBolaM(double r){
 struct bola* negra=newBola();
 bola_setRadius(negra,r);
 double s=bola_getSurface(negra);
 MLPutReal64(stdlink,s);
}
int main(int argc, char* argv[])
{
  return MLMain(argc, argv);
}

I have not being able to link and create the executable files from the CCompilerDriver package functions within Mathematica. But I obtained the needed libraries and include directories from its CreateExecutable function using the option "ShellCommandFunction" :> Print . After that, I can build from the shell (or maybe using Run).

> g++ -Wall -c bola_cWrap.cpp
> ./mprep -o surfaceBolaMtm.c surfaceBolaM.tm
> gcc -Wall -c  -m64 -fPIC -O2 -I "$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/IncludeFiles/C" -I "$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/Links/MathLink/DeveloperKit/Linux-x86-64/CompilerAdditions"  surfaceBolaMtm.c surfaceBolaM.c -L"$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/Links/MathLink/DeveloperKit/Linux-x86-64/CompilerAdditions" -L "$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/Libraries/Linux-x86-64" -l"ML64i3" -lm -lpthread -lrt -lstdc++
> g++ -Wall -I "$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/IncludeFiles/C" -I "$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/Links/MathLink/DeveloperKit/Linux-x86-64/CompilerAdditions" surfaceBolaMtm.o surfaceBolaM.o bola_cWrap.o bola.o -o surfaceBolaM -L"$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/Links/MathLink/DeveloperKit/Linux-x86-64/CompilerAdditions" -L "$MATH_INSTALL_DIR/Wolfram/Mathematica/9.0/SystemFiles/Libraries/Linux-x86-64" -l"ML64i3" -lm -lpthread -lrt -lstdc++

And it creates the executable "surfaceBolaM". I am sure I am parsing some options to the g++ compiler which do not make much sense, but it did not complain.

Finally, you can install the executable in Mathematica

In[1]:=Clear[link]; link =Install["surfaceBolaM"]; Print[link];
     ./surfaceBolaM
In[2]:= (surfaceBolaM[2.55555]/4/Pi)^.5
Out[2]= 2.55555
In[3]:=Uninstall[link]
Out[3]="./surfaceBolaM"

Just in case, here are the sources for "bola.cpp" and "bola.h"

// (*bola.h*)
#ifndef BOLA_H
#define BOLA_H
class bola{
private:
 double m_radius;
public:  
 void setRadius(double radius);
 double getSurface();
 ~bola(){}
};
#endif

// (*bola.cpp*)
#include <cmath>
#include "bola.h"
void bola::setRadius(double radius){m_radius=radius;}
double bola::getSurface(){return(12.5664*pow(m_radius,2));}

I have suffered with this. I am kind of annoyed by the Mathematica documentation which refers in many places to "C/C++" stuff when it is not quite the same. It was quite an additional effort to learn the C++ details after learning the mathlink integration with C, specially for people (like me) not familiar with any of these two languages.

$\endgroup$
  • 2
    $\begingroup$ The required compiler options are explained here. -luuid is needed only from Mathematica 10.0 onwards. I don't think -m64 -fPIC are needed. $\endgroup$ – Szabolcs May 25 '16 at 17:45
  • $\begingroup$ Also, extern "C" should only be needed for the prototype (declaration), not for the definition of the functions. $\endgroup$ – Szabolcs May 25 '16 at 17:48
  • $\begingroup$ @Szabolcs It did not link at the end without that extern C in "bola_cWrap.cpp" $\endgroup$ – user13427 May 25 '16 at 17:53
  • $\begingroup$ The extern in "surfaceBolaM.c" apparently is not needed. $\endgroup$ – user13427 May 25 '16 at 18:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy