使用 Protocol Buffers 描述符对象从 .proto 文件中读取注释
Reading comments from .proto files using a Protocol Buffers descriptor object
我目前正在使用 Google Protocol Buffers.
重新访问一个项目
在项目中我想利用 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
文件中进行注释,
但其中 none 似乎有效:
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。
谁能指导我正确的方向and/or给我提供一个工作示例?
编辑 2015-09-24:
在阅读了官方文档中的 Self Describing Messages 部分并测试了很多东西之后,在我看来,我对 protobuf 描述符有了更好的理解。
如果以下一个或多个陈述不正确,请纠正我:
- 如果另一端不知道 .proto 定义,
SelfDescribingMessage
proto 仅有用。
- 访问原型定义注释的唯一方法是使用
protoc
应用程序创建一个 .desc 文件。
- 要获取评论,GetSourceLocation 成员函数只能在 "top" 元素为
FileDescriptorSet
、FileDescriptorProto
或 FileDesriptor
时使用。如果这是正确的,Protocol Buffers 的 API 设计很差,因为 google::protobuf::Message
class 是神 Class(提供对完整文件描述符的访问 API ,但根本没有提供值)。
- 调用
concrete_message.descriptor()->file()
不(和不能)包含源注释信息,因为它不是编译代码的一部分。
在我看来,完成这项工作的唯一方法是:
使用以下参数为 theMessage.proto 文件(引用所有其他消息)调用协议:
--include_imports --include_source_info and --descriptor_set_out=message.desc
将 message.desc
文件与 application/library 一起发送,以便能够在运行时读取它(见下文)。
- 从该文件创建
google::protobuf::FileDescriptorSet
。
- 遍历
FileDescriptorSet
的所有 google::protobuf::FileDescriptorProto
。
- 使用
google::protobuf::DescriptorPool::BuildFile()
. 将每个 FileDescriptorProto 转换为 google::protobuf::FileDescriptor
- 使用应用于
FileDescriptor
实例的 Find…
函数之一查找消息 and/or 字段。
- 在 message/field 描述符实例上调用函数
GetSourceLocation
。
- 通过
google::protobuf::SourceLocation::leading_comments
和 google::protobuf::SourceLocation::trailing_comments
阅读评论。
这对我来说似乎很复杂,所以我还有两个问题:
- 没有不使用 FileDescriptorSet 就可以包含源信息的方法吗?
- 是否可以 "connect"/设置
FileDescriptorSet
使用具体的消息 class/instance,因为那样会大大简化事情?
编辑 2015-09-25: 由 上帝 Class 我的意思是 Message
class and/or 描述符 classes 提供 public 或多或少无用的功能,因为它们在客户端使用时不提供任何信息。以"normal"消息为例: 所以生成的代码不包含源注释信息,因此所有描述符classes中的GetSourceLocation
方法(例如 Descriptor
和 FieldDescriptor
) 是完全没用的。从逻辑角度来看,如果处理消息,应提供单独的实例 DescriptorLite
和 FieldDescriptorLite
,如果处理来自 FileDescriptorSet
的信息(其来源通常是从 .proto 文件生成的 .desc 文件)。 [...]Lite
class 将成为 "normal" class 的父 class。 protoc
可能永远不会包含来源注释的论点强调了我的观点。
"connecting",我的意思是一个 API 函数来 更新 消息中的描述符信息和来自 .desc 文件的描述符信息(它如果我理解正确的话,它始终是消息提供的描述符的超集)。
看来你已经基本明白了。
您正在深入了解协议编译器中的 API,这些 API 并非真正为 public 消费而设计。它变得复杂,因为没有人编写帮助层来简化事情,因为没有多少人使用这些功能。
我不确定你所说的 Message
是 "God class" 是什么意思。 Message
只是 protobuf 实例的抽象接口。描述符描述了 类型 的 protobuf 实例。 Message::getDescriptor()
return是消息的类型,但除此之外,这些 API 之间没有太多直接联系...
Isn't there a way to include the source information without using a FileDescriptorSet?
有意从嵌入到生成代码中的描述符中剥离注释,因此您需要单独 运行 解析器,生成描述符集,并动态使用它。
Is it possible to "connect"/set the FileDescriptorSet with a concrete Message class/instance, since that would drastically simplify things?
你的意思是你想要 Message::getDescriptor() 到 return 一个包含来自源文件的评论数据的描述符?这将需要将评论数据嵌入到生成的代码中,这对于 protoc
的实现来说是微不足道的(它目前有意将它们删除,因此它只需要 而不是 这样做)但可能会膨胀和危险(可能会泄露使用 protobufs 构建的闭源二进制文件的人的秘密)。
我目前正在使用 Google Protocol Buffers.
重新访问一个项目在项目中我想利用 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
文件中进行注释,
但其中 none 似乎有效:
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。
谁能指导我正确的方向and/or给我提供一个工作示例?
编辑 2015-09-24:
在阅读了官方文档中的 Self Describing Messages 部分并测试了很多东西之后,在我看来,我对 protobuf 描述符有了更好的理解。
如果以下一个或多个陈述不正确,请纠正我:
- 如果另一端不知道 .proto 定义,
SelfDescribingMessage
proto 仅有用。 - 访问原型定义注释的唯一方法是使用
protoc
应用程序创建一个 .desc 文件。 - 要获取评论,GetSourceLocation 成员函数只能在 "top" 元素为
FileDescriptorSet
、FileDescriptorProto
或FileDesriptor
时使用。如果这是正确的,Protocol Buffers 的 API 设计很差,因为google::protobuf::Message
class 是神 Class(提供对完整文件描述符的访问 API ,但根本没有提供值)。 - 调用
concrete_message.descriptor()->file()
不(和不能)包含源注释信息,因为它不是编译代码的一部分。
在我看来,完成这项工作的唯一方法是:
使用以下参数为 theMessage.proto 文件(引用所有其他消息)调用协议:
--include_imports --include_source_info and --descriptor_set_out=message.desc
将
message.desc
文件与 application/library 一起发送,以便能够在运行时读取它(见下文)。- 从该文件创建
google::protobuf::FileDescriptorSet
。 - 遍历
FileDescriptorSet
的所有google::protobuf::FileDescriptorProto
。 - 使用
google::protobuf::DescriptorPool::BuildFile()
. 将每个 FileDescriptorProto 转换为 - 使用应用于
FileDescriptor
实例的Find…
函数之一查找消息 and/or 字段。 - 在 message/field 描述符实例上调用函数
GetSourceLocation
。 - 通过
google::protobuf::SourceLocation::leading_comments
和google::protobuf::SourceLocation::trailing_comments
阅读评论。
google::protobuf::FileDescriptor
这对我来说似乎很复杂,所以我还有两个问题:
- 没有不使用 FileDescriptorSet 就可以包含源信息的方法吗?
- 是否可以 "connect"/设置
FileDescriptorSet
使用具体的消息 class/instance,因为那样会大大简化事情?
编辑 2015-09-25: 由 上帝 Class 我的意思是 Message
class and/or 描述符 classes 提供 public 或多或少无用的功能,因为它们在客户端使用时不提供任何信息。以"normal"消息为例: 所以生成的代码不包含源注释信息,因此所有描述符classes中的GetSourceLocation
方法(例如 Descriptor
和 FieldDescriptor
) 是完全没用的。从逻辑角度来看,如果处理消息,应提供单独的实例 DescriptorLite
和 FieldDescriptorLite
,如果处理来自 FileDescriptorSet
的信息(其来源通常是从 .proto 文件生成的 .desc 文件)。 [...]Lite
class 将成为 "normal" class 的父 class。 protoc
可能永远不会包含来源注释的论点强调了我的观点。
"connecting",我的意思是一个 API 函数来 更新 消息中的描述符信息和来自 .desc 文件的描述符信息(它如果我理解正确的话,它始终是消息提供的描述符的超集)。
看来你已经基本明白了。
您正在深入了解协议编译器中的 API,这些 API 并非真正为 public 消费而设计。它变得复杂,因为没有人编写帮助层来简化事情,因为没有多少人使用这些功能。
我不确定你所说的 Message
是 "God class" 是什么意思。 Message
只是 protobuf 实例的抽象接口。描述符描述了 类型 的 protobuf 实例。 Message::getDescriptor()
return是消息的类型,但除此之外,这些 API 之间没有太多直接联系...
Isn't there a way to include the source information without using a FileDescriptorSet?
有意从嵌入到生成代码中的描述符中剥离注释,因此您需要单独 运行 解析器,生成描述符集,并动态使用它。
Is it possible to "connect"/set the FileDescriptorSet with a concrete Message class/instance, since that would drastically simplify things?
你的意思是你想要 Message::getDescriptor() 到 return 一个包含来自源文件的评论数据的描述符?这将需要将评论数据嵌入到生成的代码中,这对于 protoc
的实现来说是微不足道的(它目前有意将它们删除,因此它只需要 而不是 这样做)但可能会膨胀和危险(可能会泄露使用 protobufs 构建的闭源二进制文件的人的秘密)。