Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

change function pointer from library A in library B

My situation is the following:

I am writing a toolbox that generates two libraries. The first (A) has all the functions and data-types and can be used in a pure C++ application; the second (B) is an interface to MATLAB. A pure C++ program would be compiled with

g++ $(FLAGS) C.cpp $(MOREFLAGS) -lA

while a MATLAB program would be compiled with B linked after A, i.e.

mex $(FLAGS) C.cpp $(MOREFLAGS) -lA -lB

Now, I would like use a function pointer (myexit) to call std::exit() for pure C++ applications and mex_exit() (which calls mexErrMsgTxt()) for MATLAB applications. Following a tutorial on function pointers, I've written something like the snippets below (everything is actually within a namespace, but I have suppressed this for brevity).

//A.hpp
#ifndef __A
#define __A
extern void (*myexit)(int);
...
#ifdef mex_h /* defined in mex.h */
#include "B.hpp"
#endif /* mex_h */
#endif /* __A */

//A.cpp
#include "A.hpp"
void (*myexit)(int) = &std::exit;

//B.hpp
#ifndef __B
#define __B
#include <mex.h>
#include "A.hpp"
...
void mex_exit(int);
#endif /* __B */

//B.cpp
#include <mex.h>
#include "A.hpp"
void mex_exit(int err) {mexPrintf("Error code %d\n",err); mexErrMsgTxt("...");}
//void (*myexit)(int) = &mex_exit; // <- I want a line like this to override the line in A.cpp

What I have above seems to work for pure C++ code and I find that I can get the right behaviour for MATLAB code if I include the line myexit = &mex_exit; in C.cpp, however, I want this behaviour simply from having #include <mex.h> and #include "A.hpp" in C.cpp and linking to B (i.e. it shouldn't be the user's responsibility to include this line).

Is this possible? If so, then how?

like image 460
Brett Ryland Avatar asked Jun 27 '26 07:06

Brett Ryland


2 Answers

In library B, add a static constructor to set myexit:

// Consider putting this into a namespace
extern void (*myexit)(int);

// anonymous namespace to avoid name collisions
namespace {
class StaticInit {
  StaticInit() {
    myexit = mex_exit;
  }
} static_init_obj;
}

Then link library B to depend on library A:

gcc -o libB.so -shared -lA -lmatlab b.o

Because libB depends on libA, libA static constructors will be invoked before libB static constructors, so ordering isn't a problem. The StaticInit constructor will be invoked during program startup (before main()), and set myexit for you.

like image 50
bdonlan Avatar answered Jun 28 '26 20:06

bdonlan


You could apply the GCC constructor function attribute to a function in B.cpp, which overwrites the value of myexit.

Not portable, of course.

like image 45
Oliver Charlesworth Avatar answered Jun 28 '26 22:06

Oliver Charlesworth