如何正确地混合C ++和C.

我遇到了一些问题:我需要为C ++库编写一个C包装器。 说我有3个文件:

  • wrapper.h

    typedef struct Foo Foo; Foo* create_foo(); 
  • wrapper.cpp

     extern "C" { #include "wrapper.h" } #include "foo.h" Foo* create_foo() { return new Foo; } 
  • foo.h中

     class Foo { public: Foo(); }; 

编译好:

clang++ -std=c++14 wrapper.cpp foo.h wrapper.h -shared -fPIC

clang++ -shared -o libbindings.so a.out

但是在编译使用C包装器的程序时(它是编译器并通过使用包装器 – Crystal的编程语言链接),我得到一个未定义的引用create_foo()和链接器错误collect2: error: ld returned 1 exit status 。 我该如何调试(以及我做错了什么)?

这是一个工作示例:

wrapper.h (C&C ++感知)

 #ifndef WRAPPER_H_ #define WRAPPER_H_ #ifdef __cplusplus extern "C" { #endif typedef struct CPPClass CPPClass; CPPClass* CPPClass_new(); void CPPClass_do_something(CPPClass* cppclass); int CPPClass_get_state(CPPClass* cppclass); void CPPClass_delete(CPPClass* cppclass); #ifdef __cplusplus } #endif #endif /* WRAPPER_H_ */ 

wrapper.cpp (仅限C ++)

 #include "wrapper.h" class CPPClass { int state; public: CPPClass(): state(0) {} void do_something() { ++state; } int get_state() const { return state; } }; extern "C" CPPClass* CPPClass_new() { return new CPPClass; } extern "C" void CPPClass_do_something(CPPClass* cppclass) { cppclass->do_something(); } extern "C" int CPPClass_get_state(CPPClass* cppclass) { return cppclass->get_state(); } extern "C" void CPPClass_delete(CPPClass* cppclass) { delete cppclass; } 

use-wrapper.c (仅限C)

 #include  #include "wrapper.h" int main(void) { CPPClass* cppclass = CPPClass_new(); if(!cppclass) { printf("ERROR: failed to create CPPClass:\n"); return 1; } printf("state: %d\n", CPPClass_get_state(cppclass)); CPPClass_do_something(cppclass); printf("state: %d\n", CPPClass_get_state(cppclass)); CPPClass_delete(cppclass); } 

编译CPP

 g++ -std=c++11 -shared -fPIC -o libwrapper.so wrapper.cpp 

编译C.

 gcc -o use-wrapper use-wrapper.c -L. -lwrapper -lstdc++ 

输出:

 $ ./use-wrapper state: 0 state: 1 

希望有所帮助。

您正在创建一个名为a.out的共享对象,然后是另一个名为libbindings.so共享对象,它表面上链接到a.out但不引用任何内容。 现在,如果一组输入文件没有任何未定义的符号,则不会搜索任何库或将其添加到输出中。 所以libbindings.so本质上是一个空库。 校验:

  % nm a.out | grep create_foo 00000000000006bc T create_foo % nm libbindings.so | grep create_foo % 

如果你有几个源文件,你应该从每个源构建一个目标文件(使用-c compilation标志),(然后可选地将对象组合成一个静态库 – 如果你没有发布静态库,则跳过这一步)然后构建来自先前构建的对象的共享对象:

  clang++ -c -fPIC foo.cpp clang++ -c -fPIC bar.cpp clang++ -shared -o libfoobar.so foo.o bar.o 

如果您只有一个源或很少的源文件,您可以轻松地一起编译,您可以一步构建共享库:

  clang++ -std=c++14 wrapper.cpp somethingelse.cpp -shared -fPIC -o libbindings.so 

不建议用于大型项目。