4

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.

3
  • 1
    possible duplicate of What is __gxx_personality_v0 for? Commented May 29, 2013 at 19:00
  • I'd seen that question, but if an answer to my problem is contained within I've failed to understand it. Commented May 29, 2013 at 19:09
  • 2
    There are lots of duplicates, but perhaps I haven't picked the best one. Anyway, the solution is in the first answer at the question I linked; either link with G++, or add -lstdc++. Commented May 29, 2013 at 19:13

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I tried linking with g++, and got the same result. But giving -lstdc++ to GHC works, which I hadn't thought of. Thanks!
0

If you want to have C++ code in C code, use extern "C++" around all the C++ code which your C program uses. Then you can compile it as a C program and Haskell wouldn't even know that it's implemented using some C++ code behind the scenes.

EDIT: I never tried this direction (usually you use C code in a C++ project), but basically this is how it's supposed to work.

If it doesn't just work, try compiling the C++ program like any normal C++ program with g++, then write a C program which uses it.

Comments

0

I would try adding extern "C" to c++ functions that will be called in C. The C++ compiler must know that the function is to be called by a C compiler using the extern "C" construct.

// In your C++ code

// Declare function(char, int) as a c function using extern "C": extern "C" void function(char c, int i);

...

// Implement function(char,int) in C++ module: void function(char c, int i) { ... }

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.