Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

protocol buffers - generate NON-inline accessors

We're using protocol buffers (2.4.1) in a medium size embedded system w/ c# an c++ code. We use protobufs to isolate our managed and native layers w/ an easy to maintain serialization layer (For the curious, we would have just used Pinvoke, but we also have to run native code in a separate process on test/simulators).

Our system has a number of DLL's, and I have the generated native protobuf code in it's own DLL so that the other parts of the system can don't have to link in the generated code directly.

The problem i'm having is that all the generated accessors are inline, eg:

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

use the generated API in size (the 'default_instance_' is dereferenced and accessed if this particular field not set). This means that I can't link (lnk2001) any clients using the accessors because there is not symbol default_instance_

I think the typical use case for ProtoBufs would be to have each component link in the generated protobuf code itself (after all, this is primarily a serialization layer for distributed systems), but

I'm wondering if there is a compile switch to change the inlining behavior that I missed. (Have all accessors defined in the CC file, not H)

Thanks!


  • Thanks @g-makulik! Looks like the answer was about 30 lines up in the ProtoC code, i just didn't see it :)

    • < see his answer below for the bulk of the solution > This should also help you, though.

As noted in some of Kenton's changelogs, adding this causes several warnings (C4251, c4275) relating to base classes that are not also DLLEXPORT'd

with the way ProtoBufs is implemented, and the protobuf classes being all templates, these warnings are benign. To cleanly ignore them (eg WITHOUT having to disable the warnings for all clients) I used this somewhat hacky approach:

-wrapper for the protobuf.h file that eveyone includes. (no one include the real generated H file)

    #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)  

and a wrapper C file (the real protobuf CC file is not in my project -> not built directly)

#include "MyProtoFile_WRAPPER.h"  
#include "MyProtoFile.cc"
like image 883
some bits flipped Avatar asked Jul 31 '13 20:07

some bits flipped


People also ask

How does Protobuf serialize?

The Protobuf serialization mechanism is given through the protoc application, this compiler will parse the . proto file and will generate as output, source files according to the configured language by its arguments, in this case, C++. You can also obtain more information about, reading the section compiler invocation.

What is protocol buffers gRPC?

Protocol buffers are a combination of the definition language (created in . proto files), the code that the proto compiler generates to interface with data, language-specific runtime libraries, and the serialization format for data that is written to a file (or sent across a network connection).

How do you deprecate a field in Protobuf?

Protobuf has an option for marking a “field” as deprecated. optional int32 old_field = 6 [deprecated=true]; Full snipped from their documentation: deprecated (field option): If set to true , indicates that the field is deprecated and should not be used by new code.


1 Answers

I think this link could answer your question: Protobuf with MSVC: how to export generated Message

Quote from Kenon Varga (Project leader of google protobuf):

If you invoke protoc like:

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

then it will generate code with MY_EXPORT_MACRO in all the right places. However, this option is incomplete -- currently there is no way to force the generated .pb.h to #include a header which defines MY_EXPORT_MACRO. I'm open to patches to fix this. Or, you could use a hack to work around it, such as adding the #include via some sort of text processing after protoc finishes, or perhaps moving the .pb.h to .pb2.h and replacing the .pb.h file with one that first includes your header then includes the .pb2.h...

And additonally to cover the mentioned incompleteness (Quote from Aron Bierbaum):

We currently get around this limitation by forcing the the header to be included using compiler command line flags:

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

NOTE:
Using the inline keyword shouldn't be relevant in this case (that an additional __declspec dllexport/__declspec dllimport attribute is put on the accessor method). Per definition it's up to the compiler to inline functions or not. Of course seeing a __declspec dllexport or __declspec dllimportattribute is contradictionary for inlining.

like image 187
πάντα ῥεῖ Avatar answered Oct 04 '22 06:10

πάντα ῥεῖ