6

我们在带有 c# 和 c++ 代码的中型嵌入式系统中使用协议缓冲区(2.4.1)。我们使用 protobufs 来隔离我们的托管层和本机层,并带有一个易于维护的序列化层(出于好奇,我们可能只使用了 Pinvoke,但我们还必须在测试/模拟器上的单独进程中运行本机代码)。

我们的系统有很多 DLL,我在它自己的 DLL 中有生成的本机 protobuf 代码,这样系统的其他部分就不必直接链接到生成的代码中。

我遇到的问题是所有生成的访问器都是inline,例如:

inline const ::MyProtoClassName::MyField& MyProtoClassName::myfield() const 
{ 
   return myfield_ != NULL ? *myfield_ : *default_instance_->myfield_; 
}

使用生成的 API 大小(如果未设置此特定字段,则取消引用并访问“ default_instance_ ”)。这意味着我无法使用访问器链接(lnk2001)任何客户端,因为没有符号 default_instance_

我认为 ProtoBufs 的典型用例是在生成的 protobuf 代码本身中拥有每个组件链接(毕竟,这主要是分布式系统的序列化层),但是

我想知道是否有一个编译开关来改变我错过的内联行为。(在 CC 文件中定义所有访问器,而不是 H)

谢谢!


  • 谢谢@g-makulik!看起来答案在 ProtoC 代码中大约有 30 行,我只是没看到 :)

    • <请参阅下面的大部分解决方案的答案> 不过,这也应该对您有所帮助。

正如在 Kenton 的一些变更日志中所指出的,添加这会导致几个与基类相关的警告(C4251、c4275),这些基类也不是 DLLEXPORT'd

使用 ProtoBufs 的实现方式,并且 protobuf 类都是模板,这些警告是良性的。为了完全忽略它们(例如,不必禁用所有客户端的警告),我使用了这种有点 hacky 的方法:

-everyone 包含的 protobuf.h 文件的包装器。(没有人包含真实生成的H文件)

    #pragma once
    #pragma warning(push)  
    #pragma warning(disable:4251)  
    #pragma warning(disable:4275)  
    // include the protobuf generated code; but exclude the warn c4251, c4275  
    // these relate to the dll exported     
    #include "yourProtoFile.h"  
    #pragma warning(pop)  

和一个包装 C 文件(真正的 protobuf CC 文件不在我的项目中 -> 不是直接构建的)

#include "MyProtoFile_WRAPPER.h"  
#include "MyProtoFile.cc"
4

1 回答 1

6

我认为这个链接可以回答你的问题:Protobuf with MSVC: how to export generated Message

Kenon Varga(google protobuf 项目负责人)的引述:

如果您像这样调用 protoc:

protoc --cpp_out=dllexport_decl=MY_EXPORT_MACRO:path/to/output/dir myproto.proto

然后它将在所有正确的地方生成带有 MY_EXPORT_MACRO 的代码。然而,这个选项是不完整的——目前没有办法强制生成的 .pb.h #include 一个定义 MY_EXPORT_MACRO 的头文件。我愿意接受补丁来解决这个问题。或者,您可以使用 hack 来解决它,例如在 protoc 完成后通过某种文本处理添加#include,或者可能将 .pb.h 移动到 .pb2.h 并将 .pb.h 文件替换为一个首先包含您的标题,然后包含 .pb2.h ...

此外,为了涵盖提到的不完整性(来自 Aron Bierbaum 的引述):

我们目前通过使用编译器命令行标志强制包含头文件来绕过这个限制:

Windows:/FIproject/Config.h
Linux:-include project/Config.h

注意:
在这种情况下 使用inline关键字不应该是相关的(附加__declspec dllexport/__declspec dllimport属性放在访问器方法上)。根据定义,是否内联函数取决于编译器。当然,看到__declspec dllexportor__declspec dllimport属性与内联是矛盾的。

于 2013-07-31T21:06:16.487 回答