我目前正在使用Google Protocol Buffers重新审视一个项目。
在项目中,我想利用协议缓冲区的 Descriptors 和 Reflection 功能。
官方文档指出.proto
文件的注释可以读取:
DebugStringWithOptions()
,调用消息或描述符。GetSourceLocation()
,调用描述符。我无法检索评论,因此我认为我做的事情完全错误,或者该功能尚未在Protocol Buffers中完全实现。
以下是一些代码段:
google::protobuf::DebugStringOptions options;
options.include_comments = true;
std::cout << "google::protobuf::Descriptor::DebugStringWithOptions(): "
<< message.descriptor()->DebugStringWithOptions(options) << std::endl
<< std::endl;
const google::protobuf::FieldDescriptor* field_descriptor{
message.descriptor()->field(1)};
// TODO(wolters): Why doesn't this work?
google::protobuf::SourceLocation* source_location{
new google::protobuf::SourceLocation};
field_descriptor->GetSourceLocation(source_location);
// if (field_descriptor->GetSourceLocation(source_location)) {
std::cout << "start_line: " << source_location->leading_comments
<< std::endl;
std::cout << "end_line: " << source_location->leading_comments << std::endl;
std::cout << "start_column: " << source_location->start_column << std::endl;
std::cout << "end_column: " << source_location->end_column << std::endl;
std::cout << "leading_comments: " << source_location->leading_comments
<< std::endl;
std::cout << "trailing_comments: " << source_location->trailing_comments
<< std::endl;
// }
我已尝试在.proto
文件中使用以下两种语法进行评论,
但它们似乎都不起作用:
MessageHeader header = 1; // The header of this `Message`.
/**
* The header of this `Message`.
*/
MessageHeader header = 1;
我正在使用GCC 4.7.1(启用了C ++ 11支持)和最新的Protocol Buffers版本3.0.0-alpha-4.1。
有人可以指导我进入正确的方向和/或为我提供一个有效的例子吗?
编辑2015-09-24:
在记录官方文档中的Self Describing Messages部分并测试了大量内容之后,在我看来,我对protobuf描述符有了更好的理解。
如果以下一项或多项陈述不正确,请更正我:
SelfDescribingMessage
proto 仅有用。protoc
应用程序创建.desc文件。FileDescriptorSet
,FileDescriptorProto
或FileDesriptor
。如果这是正确的,协议缓冲区的API设计很差,因为google::protobuf::Message
类是神类(提供对完整文件描述符API的访问,但根本不提供这些值)。concrete_message.descriptor()->file()
没有(和不能)包含源注释信息,因为它不是编译代码的一部分。 在我看来,完成这项工作的唯一方法是:
使用参数为theMessage.proto文件(引用所有其他消息)调用protoc:
--include_imports --include_source_info and --descriptor_set_out=message.desc
将message.desc
文件与应用程序/库一起发送,以便能够在运行时读取它(见下文)。
google::protobuf::FileDescriptorSet
。google::protobuf::FileDescriptorProto
的所有FileDescriptorSet
进行迭代。google::protobuf::FileDescriptor
将每个FileDescriptorProto转换为google::protobuf::DescriptorPool::BuildFile()
。Find…
实例上应用FileDescriptor
函数之一查找消息和/或字段。GetSourceLocation
。google::protobuf::SourceLocation::leading_comments
和google::protobuf::SourceLocation::trailing_comments
这对我来说似乎很复杂,所以我还有两个问题:
FileDescriptorSet
设置为具体的Message类/实例,因为这会大大简化事情? 编辑2015-09-25:通过上帝类我的意思是Message
类和/或描述符类提供更多或更多的公共函数不那么无用,因为它们在客户端使用时不提供任何信息。采取正常的&#34;消息例如:因此生成的代码不包含源注释信息,因此所有描述符类(例如GetSourceLocation
和Descriptor
)中的FieldDescriptor
方法完全是无用。从逻辑角度来看,如果处理消息,则应提供单独的实例DescriptorLite
和FieldDescriptorLite
;如果处理来自Descriptor
的信息,则应提供FieldDescriptor
和FileDescriptorSet
通常是.proto文件生成的.desc文件)。然后[...]Lite
类将成为&#34; normal&#34;的父类。类。 protoc
可能永远不会包含源注释的论点强调了我的观点。
通过&#34;连接&#34;,我的意思是一个API函数,用更新消息中的描述符信息,其中包含来自.desc文件的描述符信息(它始终是.desc文件的超集消息提供的描述符,如果我理解正确的话。)
答案 0 :(得分:1)
听起来你基本上已经弄明白了。
您正深入研究协议编译器中的API,这些API并非真正为公共消费而设计。它变得复杂,因为没有人编写辅助层来简化事情,因为没有多少人使用这些功能。
我不确定你对Message
成为上帝班级&#34;的意思。 Message
仅仅是protobuf实例的抽象接口。描述符描述了protobuf实例的类型。 Message::getDescriptor()
会返回消息的类型,但除此之外,这些API之间没有多少直接连接...
是否有办法在不使用FileDescriptorSet的情况下包含源信息?
有意地从嵌入到生成代码中的描述符中删除注释,因此您需要单独运行解析器,生成描述符集并动态使用它。
是否可以&#34; connect&#34; /将FileDescriptorSet设置为具体的Message类/实例,因为这会大大简化事情?
您是否希望Message :: getDescriptor()返回包含源文件中注释数据的描述符?这需要将注释数据嵌入到生成的代码中,这对于protoc
实现来说是微不足道的(它目前有意剥离它们,所以它只需要不那样做)但潜在的膨胀和危险(可能揭示运送使用protobufs构建的闭源二进制文件的人的秘密)。