如何正確混合C++和C




ffi (2)

我對此有一些問題:我需要為C ++庫編寫一個C包裝器。 說我有3個文件:

  • 包裝器

    typedef struct Foo Foo;
    Foo* create_foo();
  • 包裝器

    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包裝程序的程序(它是編譯器並通過使用包裝程序的編程語言 collect2: error: ld returned 1 exit status 鏈接)時,我得到對create_foo()的未定義引用和鏈接器錯誤 collect2: error: ld returned 1 exit status 。 我該如何調試(我在做什麼錯)?


您正在創建一個名為 a.out 的共享庫,然後創建另一個名為 libbindings.so 共享 libbindings.so ,這表面上鍊接到 a.out 但未引用任何內容。 現在,如果一組輸入文件沒有任何未定義的符號,則不會搜索任何庫或將其添加到輸出中。 所以 libbindings.so 本質上是一個空庫。 校驗:

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

如果您有多個源文件,則應從每個源文件構建一個 目標 文件(使用-c編譯標誌),(然後可以選擇將這些對象組合到一個靜態庫中-如果不發布靜態庫則跳過此步驟),然後構建來自先前構建的對象的共享對象:

  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

不建議在大型項目中使用。


這是一個工作示例:

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 <stdio.h>
#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

希望能有所幫助。





ffi