-1

I have a shared library `libsharedlib.so' which used to be generated from C files. Since the library now needs to use functions from a 3rd party C++ library, I would like to convert my shared library from C to C++ (the code is relatively simple). Based on the differences I read here, the only adaptations I had to do were in my use of stdlib and stdio functions. The headers were changed from

#include <stdio.h>
#include <stlib.h>

To

#include <cstdlib>
#include <cstdio>

And all calls to the functions in these libraries are prefixed with the std:: namespace (e.g. std::malloc instead of malloc, I did not use using namespace std). The source file extensions were changed from .c to .cpp. I also had to add newlines at the end of each file, and had to cast my malloc's. No other compiler feedback after that. The shared library is compiled with the following command:

pgcpp -shared -I./inc/ -o ./lib/libsharedlib.so file1.cpp file2.cpp ...

And returns no errors or warnings.

I now have a MEX function, mex_gateway.cpp which calls functions from this library:

#include "sharedlibraryheader.h"
#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[],
             int nrhs, const mxArray *prhs[]){
...
function_from_library(data);
}

It is compiled with the following command

mex -L./lib/ -lsharedlib -I./inc/ mex_gateway.cpp

Which (when adding the verbose flag -v) actually executes the following commands:

g++ -c  -I./inc/ -I/opt/MATLAB/R2013b/extern/include -I/opt/MATLAB/R2013b/simulink/include -DMATLAB_MEX_FILE -ansi -D_GNU_SOURCE -fPIC -fno-omit-frame-pointer -pthread  -DMX_COMPAT_32 -O -DNDEBUG  "mex_gateway.cpp"

g++ -O -pthread -shared -Wl,--version-script,/opt/MATLAB/R2013b/extern/lib/glnxa64/mexFunction.map -Wl,--no-undefined -o  "mex_gateway.mexa64"  mex_gateway.o  -L./lib/ -lsharedlib -Wl,-rpath-link,/opt/MATLAB/R2013b/bin/glnxa64 -L/opt/MATLAB/R2013b/bin/glnxa64 -lmx -lmex -lmat -lm

I get the following error:

mex_gateway.o: In function `mexFunction':
mex_gateway.cpp:(.text+0x24e): undefined reference to `function_from_library(...arguments...)'
collect2: ld returned 1 exit status

    mex: link of ' "mex_gateway.mexa64"' failed.

Of course, I triple-checked the build commands which have the right path to the shared library and the library name. The shared library does have the definition of the function:

[user@machine]$ nm lib/libsharedlib.so | grep function_from_library
000000000000198a t __function_from_library__FPCdN51dN27iiiiPdPdPdPdPdPdEND
0000000000001360 T function_from_library__FPCdN51dN27iiiiPdPdPdPdPdPd

So where's the problem?

EDIT: My sharedlibraryheader.h file looks like this:

#ifndef __SHAREDLIBRARYHEADER_H__
#define __SHAREDLIBRARYHEADER_H__

#ifdef _cplusplus
extern "C"{
#endif

int function1 ( ... );
...
void function_from_library( ... );
...

#ifdef _cplusplus
}
#endif
#endif
lodhb
  • 929
  • 2
  • 12
  • 29

2 Answers2

4

You'll have to do something like:

extern "C" {
#include "sharedlibraryheader.h"
}

This will let the compiler know that the functions defined in sharedlibraryheader.h conform to the C ABI instead of the C++ ABI. Normally, this is handled in the header itself, in the following manner:

// Typically put headers outside extern "C"
#include "..."
#include "..."

#ifdef __cplusplus
extern "C" {
#endif

... rest of header here ...

#ifdef __cplusplus
}
#endif

You have to do this both for the code that uses the shared library AND the shared library itself, when compiling it.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • Yes, this does sound like a problem with name mangling causing the C++ compiler to generate/expect decorated function names while the C one is using plain names. – Chris Stratton Jul 25 '14 at 17:40
  • I forgot to mention that I already did that! But why whould the SO be treated as a C library when it is compiled from CPP files? – lodhb Jul 25 '14 at 17:42
  • @lodhb If you already did that, then you need to edit your question to include that information. The main reason why a linker can't find a C function called by a C++ app is the name-mangling/extern "C" issue. – PaulMcKenzie Jul 25 '14 at 17:45
  • @lodhb: Because the library itself is actually compiled from C files! But now you're recompiling its headers (as part of _your_ project) as C++, and suddenly the definitions do not match the declarations. – Lightness Races in Orbit Jul 25 '14 at 17:47
  • @PaulMcKenzie Sorry, I just modified my question! – lodhb Jul 25 '14 at 17:47
  • @LightnessRacesinOrbit How can this be, when all files are `.cpp` and are compiled by a C++ compiler (PGCPP)? – lodhb Jul 25 '14 at 17:48
0

You are aware that if there is no C++ code in the .cpp files that you are trying to compile, that you can actually compile them as C source (with GCC) and linking that into your C++ project? In makefiles that I regularly create I will do something like:

GPPWALL = g++ -Wall -c
GCCWALL = gcc -Wall -c

...

all: glxgraphics.o shadermanager.o sdlkeyboard.o sdlmouse.o main.cpp
    g++ main.cpp LevelGenerator.cpp $(ASSETSOURCE) $(GRAPHICSSOURCE) $(IOSOURCE) $(BASE)AudioManager.cpp -o avgame $(GLUTLIBS) $(GRAPHICSLIBS) $(PTHREADLIBS) $(OPENALLIBS)

...

sdlmouse.o: $(BASE)avg_mouse.c $(BASE)avg_mouse.h
    $(GCCWALL) $(BASE)avg_mouse.c $(GLUTLIBS)

Notice that I have linked the C compiled code into the C++ to avoid the 'extern C' guards which are still ultimately C++ code? This is common practice.

ButchDean
  • 70
  • 6