不用 SWIG,Go 使用 C++ 代码的方式

HorCribb 3年前

来自: http://my.oschina.net/jthmath/blog/614298?fromerr=w5tJd1x3

将C++代码用C作一次封装,就可以让Go调用了。

这是一个C++头文件:

#ifndef CGO_CPPGO_CLASS_H_  #define CGO_CPPGO_CLASS_H_    #include <stdint.h>    class X  {  public:      X(int32_t a);      ~X();      void Plus();      int32_t Func(int32_t b);  private:      int32_t m_;  };    #endif

这是对应的源文件:

#include <iostream>  using std::cout;  using std::endl;    #include "class.h"    X::X(int32_t a)      :m_{ a }  {      cout << "X::X" << endl;  }    X::~X()  {      cout << "X::~X" << endl;  }    void X::Plus()  {      m_ += 1;  }    int32_t X::Func(int32_t b)  {      return m_ + b;  }

为了让Go感知不到C++(class、std::cout等)的存在,定义一个结构体:

typedef struct _X_t  {      int unused;  }X_t;

这个结构体来充当class X的作用。

完整的C头文件如下:(这个头文件中没有任何C++特有的东西!)

#ifndef C_WRAPPER_H_  #define C_WRAPPER_H_    #include <stdint.h>    typedef struct _X_t  {      int unused;  }X_t;    #ifdef __cplusplus  #define EXTERN_C extern "C"  #else  #define EXTERN_C  #endif    EXTERN_C X_t *NewX(int32_t a); // 充当构造函数  EXTERN_C void Delete(X_t *px); // 充当析构函数  EXTERN_C void Plus(X_t *px);  EXTERN_C int32_t Func(X_t *px, int32_t b);    #endif

源文件(.cpp)如下:

#include "c-wrapper.h"  #include "class.h"    X_t *NewX(int32_t a)  {      X *px = new X{ a };      return (X_t*)px;  }    void Delete(X_t *px)  {      X *p = (X*)px;      delete p;  }    void Plus(X_t *px)  {      ((X*)px)->Plus();  }    int32_t Func(X_t *px, int32_t b)  {      return ((X*)px)->Func(b);  }

接下来,就可以在Go中包含c-wrapper.h文件:

package main    import (   "fmt"  )    /*  #cgo CPPFLAGS: -std=c++11  #include "c-wrapper.h"  */  import "C"    func main() {   px := C.NewX(3)   C.Plus(px)   var n int32 = int32(C.Func(px, 7))   fmt.Println(n)   C.Delete(px)  }

结果如下:

X::X  11  X::~X

这就实现了Go使用C++代码。

如果想在Go中使用大型C++开源库,这个方法有些麻烦(而且C++的编译比较慢),但不失为一种选择。