Чтение комментариев из файлов.proto с использованием объекта дескриптора Protocol Buffers
В настоящее время я пересматриваю проект с использованием буферов протокола Google.
В проекте я хочу использовать функции Descriptors и Reflection of Protocol Buffers.
Официальная документация гласит, что комментарии .proto
файлы можно прочитать:
- С функцией
DebugStringWithOptions()
Вызывается на сообщение или дескриптор. - С функцией
GetSourceLocation()
Вызывается по дескриптору.
Я не могу получить комментарии, поэтому я думаю, что делаю что-то не так или эта функция еще не полностью реализована в буферах протокола.
Вот некоторые фрагменты кода:
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:
После прочтения раздела " Сообщения с самоописанием" в официальной документации и тестирования многих вещей мне кажется, что я немного лучше понимаю дескрипторы protobuf.
Поправьте меня, если одно или несколько из следующих утверждений неверны:
-
SelfDescribingMessage
Proto полезен, только если другой конец не знает определения.proto. - Единственный способ получить доступ к комментариям прототипа - создать файл.desc с помощью
protoc
приложение. - Чтобы получить комментарий, функцию-член GetSourceLocation можно использовать только в том случае, если верхний элемент
FileDescriptorSet
,FileDescriptorProto
или жеFileDesriptor
, Если это правильно, у протокола Buffers плохой дизайн API, так какgoogle::protobuf::Message
class является классом God (обеспечивает доступ к полному API дескриптора файла, но значения не предоставляются вообще). - Вызов
concrete_message.descriptor()->file()
не содержит (и не может содержать) информацию об исходных комментариях, поскольку она не является частью скомпилированного кода.
Мне кажется, что единственный способ сделать эту работу:
Вызвать protoc для файла Message.proto (который ссылается на все другие сообщения) с аргументами:
--include_imports --include_source_info and --descriptor_set_out=message.desc
Корабль
message.desc
файл вместе с приложением / библиотекой, чтобы иметь возможность читать его во время выполнения (см. ниже).- Создать
google::protobuf::FileDescriptorSet
из этого файла. - Перебрать все
google::protobuf::FileDescriptorProto
изFileDescriptorSet
, - Конвертировать каждый FileDescriptorProto в
google::protobuf::FileDescriptor
с помощьюgoogle::protobuf::DescriptorPool::BuildFile()
, - Поиск сообщения и / или полей с одним из
Find…
функции, применяемые наFileDescriptor
пример. - Вызвать функцию
GetSourceLocation
на экземпляре дескриптора сообщения / поля. - Прочитайте комментарии через
google::protobuf::SourceLocation::leading_comments
а такжеgoogle::protobuf::SourceLocation::trailing_comments
,
Это кажется мне довольно сложным, поэтому у меня есть два дополнительных вопроса:
- Разве нет способа включить информацию об источнике без использования FileDescriptorSet?
- Можно ли "подключить" / установить
FileDescriptorSet
с конкретным классом / экземпляром Message, так как это значительно упростит ситуацию?
РЕДАКТИРОВАТЬ 2015-09-25: Под богом классом я имею в виду, что Message
Класс и / или классы дескрипторов предлагают общедоступные функции, которые более или менее бесполезны, поскольку они не предоставляют никакой информации при использовании клиентом. Возьмем, к примеру, "нормальное" сообщение: сгенерированный код не содержит информации об исходных комментариях, поэтому GetSourceLocation
метод во всех классах дескрипторов (например, Descriptor
а также FieldDescriptor
) совершенно бесполезно. С логической точки зрения отдельные случаи DescriptorLite
а также FieldDescriptorLite
должны быть предоставлены, если речь идет о сообщениях и Descriptor
а также FieldDescriptor
если иметь дело с информацией из FileDescriptorSet
(источником которого обычно является файл.desc, сгенерированный из файла.proto). [...]Lite
Тогда класс будет родительским классом "нормального" класса. Аргумент, что protoc
возможно, никогда не будет включать исходные комментарии, подчеркивает мою точку зрения.
Под "соединением" я подразумеваю функцию API для обновления информации дескриптора в сообщении информацией дескриптора из файла.desc (который всегда является расширенным набором дескрипторов, предоставленных сообщением, если я правильно понял).
1 ответ
Похоже, вы в основном поняли это.
Вы углубляетесь в API внутри компилятора протокола, которые на самом деле не были предназначены для публичного использования. Это становится сложным, потому что никто не написал вспомогательный слой для упрощения вещей, потому что не многие люди используют эти функции.
Я не уверен, что вы имеете в виду Message
будучи "классом Бога". Message
это просто абстрактный интерфейс для экземпляра protobuf. Дескрипторы описывают типы экземпляров protobuf. Message::getDescriptor()
возвращает тип сообщения, но кроме этого между этими API-интерфейсами нет прямой связи...
Разве нет способа включить информацию об источнике без использования FileDescriptorSet?
Комментарии намеренно удаляются из дескрипторов, встроенных в сгенерированный код, поэтому вам нужно запустить парсер отдельно, сгенерировать набор дескрипторов и использовать его динамически.
Можно ли "соединить" / установить FileDescriptorSet с конкретным классом / экземпляром Message, поскольку это значительно упростит ситуацию?
Вы имеете в виду, что вы хотите, чтобы Message::getDescriptor() возвращал дескриптор, включающий данные комментариев из исходного файла? Это потребует, чтобы данные комментариев были встроены в сгенерированный код, что было бы тривиально для protoc
реализовывать (в настоящее время он намеренно удаляет их, поэтому ему просто не нужно этого делать), но потенциально может быть вздорным и опасным (может раскрыть секреты для людей, отправляющих двоичные файлы с закрытым исходным кодом, созданные с помощью protobufs).