4

我目前正在尝试将大型 C++ 程序链接到 C“包装器”,以允许与编译器理解 C 但不理解 C++(准确地说是 Haskell GHC)的另一种语言的程序集成。但我尝试这样做,无论是使用 GHC 还是 GCC,都会遇到奇怪的问题。

为了简明扼要地模拟这种情况,假设我在 C 中有一个主程序文件:

cmain.c

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

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

  return 0;
}

以及在 .cpp 文件中定义的辅助函数:

cpp模块.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();
}
}

这么多编译就好了。但是,如果 cppmodule.cpp 引用另一个 .cpp 文件,如下所示:

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();
}
}

新的 .cpp 文件与此类似;

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

当我尝试使用“gcc cmain.o cppmodule.o morecpp.o”之类的命令进行编译时,突然出现错误;使用 g++ 编译是可行的,但正如我所提到的,这种解决方案不符合我的目的。

我试图编译这个例子的错误是

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

与我的实际项目代码进行相同类型的尝试还给出了表单错误的屏幕截图

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)'

任何见解将不胜感激。

4

3 回答 3

3

问题出在链接阶段。您的程序缺少 C++ 标准库中的符号。要解决此问题,您必须与 g++ 驱动程序链接,或者必须在 C++ 标准库中显式链接。

使用 g++ 链接是最简单的解决方案,但您也可以尝试添加-lstdc++为库标志。

请记住,仍然存在很多与此相关的陷阱。C++ ABI 并不简单,并且在编译器(clang/g++/等)甚至不同版本的 GCC 之间不一定保持一致。如果您的 Haskell 程序动态链接到使用不同 C++ ABI 编译的其他 C++ 代码,这可能是一个问题。

另请注意,您还必须在 C/C++ 边界捕获所有异常。Haskell 需要一个直接的 C ABI,并且无法处理通过 C/C++ 边界泄漏的 C++ 异常。

于 2013-05-29T19:06:39.077 回答
0

如果您想在 C 代码中extern "C++"包含 C++ 代码,请使用 C 程序使用的所有 C++ 代码。然后你可以将它编译为 C 程序,Haskell 甚至不知道它是在幕后使用一些 C++ 代码实现的。

编辑:我从未尝试过这个方向(通常你在 C++ 项目中使用 C 代码),但基本上这就是它应该如何工作的方式。

如果它不起作用,请尝试像使用 g++ 的任何普通 C++ 程序一样编译 C++ 程序,然后编写一个使用它的 C 程序。

于 2013-05-29T19:05:06.347 回答
0

我会尝试将 extern "C" 添加到将在 C 中调用的 c++ 函数中。C++ 编译器必须知道该函数将由 C 编译器使用 extern "C" 构造调用。

// 在你的 C++ 代码中

// 使用 extern "C" 将 function(char, int) 声明为 ac 函数: extern "C" void function(char c, int i);

...

// 在 C++ 模块中实现 function(char,int): void function(char c, int i) { ... }

于 2013-07-26T13:44:41.413 回答