如何为 C++、protobuf 制作 swig 接口文件
how to make swig interface file for C++, protobuf
显然,protobuf 需要知道所有涉及的 header。
以下是Header.h
的内容
Test.h是protobuf生成的header文件
#pragma once
#include "Test.h"
class TestClass
{
private:
test::Person _person;
public:
bool eventReceiveData(char*);
bool eventRecieveData(char* const);
bool eventRecieveData(std::string);
std::string getData() const;
void eventReceiveMessage(test::Person);
test::Person getPerson();
};
由于 Test.h 包括所有这些 header 文件,
#include <google/protobuf/stubs/common.h
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unknown_field_set.h>
这是否意味着我必须这样做?
%module Test
%{
#include "Header.h"
%}
%include "Header.h"
%include <google/protobuf/stubs/common.h>
%include <google/protobuf/arena.h>
%include <google/protobuf/arenastring.h>
%include <google/protobuf/generated_message_util.h>
%include <google/protobuf/metadata.h>
%include <google/protobuf/message.h>
%include <google/protobuf/repeated_field.h>
%include <google/protobuf/extension_set.h>
%include <google/protobuf/unknown_field_set.h>
另外,我是否必须包含 protobuf 的所有静态库?
我的目标语言是 C#
关于同时使用swig和protobuf的资料太少了
基于你的 protobuf object 有一个命名空间这一事实,我假设你使用的是普通的 C++ 协议。
对您的问题的简短回答是,不,您不必在 SWIG 界面中包含所有或任何 protobuf headers。不过,您可能希望在 SWIG 中包含一些或 augment/replace 它们,以使其真正完整而整洁地工作。我将向您展示如何操作,但我 坚信这不是大多数情况下的正确设计解决方案。 请参阅我在本答案末尾建议的替代方案。
作为讨论的示例,尽管我从 protobuf 教程中获取了 person.proto。我想这也是你正在使用的,但很难说,所以这里是:
message Person {
required int32 id = 1;
required string name = 2;
optional string email = 3;
}
当我们 运行 protoc 时,我们得到一个 .h 文件。如果我们从 SWIG 界面开始,例如:
%module test
%{
#include "person.pb.h"
%}
%include "person.pb.h"
然后我们生成了一个几乎无法使用的 C# 接口 - SWIG 不会整齐地包装 std::string
或 Google 的 ::google::protobuf::int32
类型,因为它对它们一无所知。
另一方面,如果我们写一个 protobuf.i 文件:
%include <std_string.i>
%include <stdint.i>
#define GOOGLE_PROTOBUF_VERSION 2006001
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2006001
namespace google {
namespace protobuf {
typedef int32 int32_t;
typedef uint8 uint8_t;
// ... whatever else you need
}
}
并在您的模块中使用它:
%module test
%include "protobuf.i"
%{
#include "person.pb.h"
%}
%include "person.pb.h"
那么现在我们开始做生意了,这是在包装界面中获得理智的最低要求。您将能够使用 C++ 在 C++ 中为您创建和管理的 protobuf objects,具有 "beanlike" 行为,即基本集和获取将可用。
还有很多东西如果不做更多的工作也将无法使用,例如描述符、元数据、消息类型、编码 io、所有权转移的字符串。
通过在您的 SWIG 界面中多做一些工作,其中的每一个都是可以修复的,但是我认为您是从错误的角度来解决这个问题的。你有一个适用于 C# 和 C++ 的 protobuf 编译器,所以我要做的是添加一个 setPerson()
和一个 getPerson()
方法,并在 SWIG 中使用 in 和 out 类型映射来序列化和透明地构造原生 C++/C# 对应类型。这是一个特别好的计划,因为故意或以其他方式你的 getPerson()
方法 returns 是私有成员的副本而不是引用,因此更改返回的底层 protobuf object 不会无论如何在 C++ 中有任何可见的效果。
显然,protobuf 需要知道所有涉及的 header。
以下是Header.h
的内容Test.h是protobuf生成的header文件
#pragma once
#include "Test.h"
class TestClass
{
private:
test::Person _person;
public:
bool eventReceiveData(char*);
bool eventRecieveData(char* const);
bool eventRecieveData(std::string);
std::string getData() const;
void eventReceiveMessage(test::Person);
test::Person getPerson();
};
由于 Test.h 包括所有这些 header 文件,
#include <google/protobuf/stubs/common.h
#include <google/protobuf/arena.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/metadata.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unknown_field_set.h>
这是否意味着我必须这样做?
%module Test
%{
#include "Header.h"
%}
%include "Header.h"
%include <google/protobuf/stubs/common.h>
%include <google/protobuf/arena.h>
%include <google/protobuf/arenastring.h>
%include <google/protobuf/generated_message_util.h>
%include <google/protobuf/metadata.h>
%include <google/protobuf/message.h>
%include <google/protobuf/repeated_field.h>
%include <google/protobuf/extension_set.h>
%include <google/protobuf/unknown_field_set.h>
另外,我是否必须包含 protobuf 的所有静态库?
我的目标语言是 C#
关于同时使用swig和protobuf的资料太少了
基于你的 protobuf object 有一个命名空间这一事实,我假设你使用的是普通的 C++ 协议。
对您的问题的简短回答是,不,您不必在 SWIG 界面中包含所有或任何 protobuf headers。不过,您可能希望在 SWIG 中包含一些或 augment/replace 它们,以使其真正完整而整洁地工作。我将向您展示如何操作,但我 坚信这不是大多数情况下的正确设计解决方案。 请参阅我在本答案末尾建议的替代方案。
作为讨论的示例,尽管我从 protobuf 教程中获取了 person.proto。我想这也是你正在使用的,但很难说,所以这里是:
message Person {
required int32 id = 1;
required string name = 2;
optional string email = 3;
}
当我们 运行 protoc 时,我们得到一个 .h 文件。如果我们从 SWIG 界面开始,例如:
%module test
%{
#include "person.pb.h"
%}
%include "person.pb.h"
然后我们生成了一个几乎无法使用的 C# 接口 - SWIG 不会整齐地包装 std::string
或 Google 的 ::google::protobuf::int32
类型,因为它对它们一无所知。
另一方面,如果我们写一个 protobuf.i 文件:
%include <std_string.i>
%include <stdint.i>
#define GOOGLE_PROTOBUF_VERSION 2006001
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2006001
namespace google {
namespace protobuf {
typedef int32 int32_t;
typedef uint8 uint8_t;
// ... whatever else you need
}
}
并在您的模块中使用它:
%module test
%include "protobuf.i"
%{
#include "person.pb.h"
%}
%include "person.pb.h"
那么现在我们开始做生意了,这是在包装界面中获得理智的最低要求。您将能够使用 C++ 在 C++ 中为您创建和管理的 protobuf objects,具有 "beanlike" 行为,即基本集和获取将可用。
还有很多东西如果不做更多的工作也将无法使用,例如描述符、元数据、消息类型、编码 io、所有权转移的字符串。
通过在您的 SWIG 界面中多做一些工作,其中的每一个都是可以修复的,但是我认为您是从错误的角度来解决这个问题的。你有一个适用于 C# 和 C++ 的 protobuf 编译器,所以我要做的是添加一个 setPerson()
和一个 getPerson()
方法,并在 SWIG 中使用 in 和 out 类型映射来序列化和透明地构造原生 C++/C# 对应类型。这是一个特别好的计划,因为故意或以其他方式你的 getPerson()
方法 returns 是私有成员的副本而不是引用,因此更改返回的底层 protobuf object 不会无论如何在 C++ 中有任何可见的效果。