c++cgccg++

How can I link C++ files to a C program?


I'm currently trying to link a big C++ program to a C "wrapper," to allow integration with a program in another language whose compiler understands C but not C++ (Haskell GHC, to be precise.) But my attempts to do so, either with GHC or GCC, meet strange problems.

To model the situation concisely, say I have a main program file in C:

cmain.c

#include "header.h"
#include <stdio.h>

int main () {
  printf("%d\n", cppfun(12));

  return 0;
}

and a helper function defined in a .cpp file:

cppmodule.cpp

#include "header.h"
#include "further.h"

class foobar {
public:
  int getfive () {return 5;}
};

extern "C" { 
int cppfun(int foo) {
  foobar fb;

  return fb.getfive();
}
}

This much will compile just fine. But if, instead, cppmodule.cpp refers to a further .cpp file, like so:

cppmodule.cpp mk II

#include "header.h"
#include "further.h"

class foobar {
public:
  int getfive () {return 5;}
};

extern "C" { 
int cppfun(int foo) {
  foobar fb;

  return fb.getfive() + morecpp();
}
}

where the new .cpp file is something similar;

morecpp.cpp

#include "further.h"

class moreobjects {
public:
  int getsix() {return 6;}
};


#ifdef __cplusplus
extern "C" {
#endif


int morecpp() {
  moreobjects mo;

  return mo.getsix();
}

#ifdef __cplusplus
}
#endif

I suddenly get an error when I'm trying to compile with a command like "gcc cmain.o cppmodule.o morecpp.o"; compiling with g++ works but, as I mentioned, this kind of solution doesn't fit my purposes.

The error I get trying to compile this example is

max@SoutheastCorner:~/Projectsync/maketest$ gcc cmain.o cppmodule.o morecpp.o
cppmodule.o:(.eh_frame+0x4b): undefined reference to `__gxx_personality_v0'
collect2: error: ld returned 1 exit status

The same kind of attempt with my actual project code additionally gives screenfulls of errors of the form

hopnode.cpp:(.text._ZN9__gnu_cxx13new_allocatorISt10_List_nodeI4nodeIPcS3_EEE8allocateEmPKv[_ZN9__gnu_cxx13new_allocatorISt10_List_nodeI4nodeIPcS3_EEE8allocateEmPKv]+0x4d): undefined reference to `operator new(unsigned long)'
/tmp/ccaoEEFM.o: In function `__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<char* const, node<char*, char*> > > >::allocate(unsigned long, void const*)':
hopnode.cpp:(.text._ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKPc4nodeIS3_S3_EEEE8allocateEmPKv[_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKPc4nodeIS3_S3_EEEE8allocateEmPKv]+0x2c): undefined reference to `std::__throw_bad_alloc()'
hopnode.cpp:(.text._ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKPc4nodeIS3_S3_EEEE8allocateEmPKv[_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKPc4nodeIS3_S3_EEEE8allocateEmPKv]+0x46): undefined reference to `operator new(unsigned long)'

Any insights would be greatly appreciated.


Solution

  • The problem is at the link stage. Your program is missing the symbols from the C++ standard library. To fix this, you have to either link with the g++ driver or you have to explicitly link in the C++ standard library.

    Linking with g++ is the easiest solution, but you can also try adding -lstdc++ as a library flag.

    Keep in mind that there are still a lot of pitfalls associated with this. The C++ ABI is not simple, and is not necessarily consistent across compilers (clang/g++/etc.) or even different versions of GCC. This can be a problem if your Haskell program dynamically links to other C++ code compiled with a different C++ ABI.

    Also note that you also must catch all exceptions at the C/C++ boundary. Haskell expects a straight C ABI and cannot deal with C++ exceptions that leak through the C/C++ boundary.