如何为 C++、protobuf 制作 swig 接口文件

Posted

技术标签:

【中文标题】如何为 C++、protobuf 制作 swig 接口文件【英文标题】:how to make swig interface file for C++, protobuf 【发布时间】:2017-01-25 11:03:25 【问题描述】:

显然,protobuf 需要知道所有涉及的标头。

下面是Header.h的内容

Test.h是protobuf生成的头文件

#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 包含所有这些头文件,

#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 的信息太少了。

【问题讨论】:

我大概可以回答这个问题,但是你为什么不把它序列化并通过 IPC 呢? 抱歉,我不知道我在做什么,哈哈 【参考方案1】:

基于您的 protobuf 对象具有命名空间这一事实,我假设您使用的是普通的 C++ 协议。

您的问题的简短回答是不,您不必在 SWIG 界面中包含所有或任何 protobuf 标头。不过,您可能希望在 SWIG 中包含一些或增加/替换它们,以使其真正完整而整洁地工作。我将向您展示如何做到这一点,但我坚信这不是大多数情况下的正确设计解决方案。请参阅此答案末尾的我建议的替代方案。

虽然我从 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++ 中以“beanlike”行为为您创建和管理的 protobuf 对象,即基本集合和获取将可用。

不过,如果没有更多的工作,很多东西也将无法使用,例如描述符、元数据、消息类型、编码 io、所有权转移的字符串。

这些都可以通过在 SWIG 界面中进行更多工作来解决,但是我认为您从错误的角度解决了这个问题。你有一个适用于 C# 和 C++ 的 protobuf 编译器,所以我要做的是添加一个 setPerson() 和一个 getPerson() 方法,并在 SWIG 中使用输入和输出类型映射来序列化和构建本机 C++ /C# 透明地对应类型。这是一个特别好的计划,因为您的 getPerson() 方法故意或以其他方式返回的是私有成员的副本而不是引用,因此更改返回的底层 protobuf 对象无论如何都不会在 C++ 中产生任何可见的影响。

【讨论】:

如果有帮助的话,我可能会详细说明该问题的最后一部分,但我需要先获得一个用于 C# 的 protobuf 编译器与 Mono 一起使用。 我不知道我在“错误的角度”部分做了什么。问题更明显知道!

以上是关于如何为 C++、protobuf 制作 swig 接口文件的主要内容,如果未能解决你的问题,请参考以下文章

如何为指针引用定义 SWIG 类型映射?

如何为 wchar_t 定义 swig typmap 以与 Perl 脚本绑定?

如何为双指针结构参数应用 SWIG 类型映射

如何为 Python 制作 C++ 库

如何为这个 C++ Windows 项目制作“make.bat”?

如何为我的 GIF tilesheet 制作动画(OpenGL、DevIL、C++)