如何将C++文件链接到C程序中?

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文件中定义了一个帮助函数:

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

这段代码可以很好地编译。但是,如果 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)'

任何见解都将不胜感激。

1
可能是重复的问题:What is __gxx_personality_v0 for? - Oliver Charlesworth
我看过那个问题,但如果我的问题的答案包含在其中,我就没能理解它。 - Maxander
2
有很多重复的内容,但也许我没有选择最好的一个。无论如何,解决方案在我链接的问题的第一个答案中;要么使用G++链接,要么添加-lstdc++ - Oliver Charlesworth
3个回答

3
问题出现在链接阶段。您的程序缺少C++标准库中的符号。为了解决这个问题,您需要使用g++驱动程序进行链接,或者显式地链接C++标准库。
使用g++进行链接是最简单的解决方案,但您也可以尝试将-lstdc++添加为库标志。
请记住,仍然存在许多陷阱。 C++ ABI不简单,并且在编译器(clang/g++/等)或甚至不同版本的GCC之间甚至不一致。如果您的Haskell程序动态链接到使用不同C++ ABI编译的其他C++代码,则可能会出现问题。
还要注意,您还必须在C/C++边界处捕获所有异常。 Haskell期望一个直接的C ABI,并且无法处理从C/C++边界泄漏的C++异常。

我尝试使用g++进行链接,结果相同。但是将-lstdc++提供给GHC可以工作,这是我没有想到的。谢谢! - Maxander

0
如果你想在C代码中使用C++代码,可以在所有C++代码周围使用extern "C++"。然后你就可以将其编译为C程序,Haskell甚至不会知道它是使用一些C++代码实现的。
编辑:我从未尝试过这个方向(通常你在C++项目中使用C代码),但基本上它应该是这样工作的。
如果它不能正常工作,请尝试像编译任何普通的C++程序一样使用g++编译C++程序,然后编写一个使用它的C程序。

0

我建议尝试添加extern "C"到C++函数中,以便在C语言中调用。C++编译器必须知道要使用extern "C"来调用该函数。

// 在你的C++代码中

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

...

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接