Чтение комментариев из файлов.proto с использованием объекта дескриптора Protocol Buffers

В настоящее время я пересматриваю проект с использованием буферов протокола Google.

В проекте я хочу использовать функции Descriptors и Reflection of Protocol Buffers.

Официальная документация гласит, что комментарии .proto файлы можно прочитать:

  1. С функцией DebugStringWithOptions() Вызывается на сообщение или дескриптор.
  2. С функцией 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.

Поправьте меня, если одно или несколько из следующих утверждений неверны:

  1. SelfDescribingMessage Proto полезен, только если другой конец не знает определения.proto.
  2. Единственный способ получить доступ к комментариям прототипа - создать файл.desc с помощью protoc приложение.
  3. Чтобы получить комментарий, функцию-член GetSourceLocation можно использовать только в том случае, если верхний элемент FileDescriptorSet, FileDescriptorProto или же FileDesriptor, Если это правильно, у протокола Buffers плохой дизайн API, так как google::protobuf::Message class является классом God (обеспечивает доступ к полному API дескриптора файла, но значения не предоставляются вообще).
  4. Вызов concrete_message.descriptor()->file() не содержит (и не может содержать) информацию об исходных комментариях, поскольку она не является частью скомпилированного кода.

Мне кажется, что единственный способ сделать эту работу:

  1. Вызвать protoc для файла Message.proto (который ссылается на все другие сообщения) с аргументами:

    --include_imports --include_source_info and --descriptor_set_out=message.desc
    
  2. Корабль message.desc файл вместе с приложением / библиотекой, чтобы иметь возможность читать его во время выполнения (см. ниже).

  3. Создать google::protobuf::FileDescriptorSet из этого файла.
  4. Перебрать все google::protobuf::FileDescriptorProto из FileDescriptorSet,
  5. Конвертировать каждый FileDescriptorProto в google::protobuf::FileDescriptor с помощью google::protobuf::DescriptorPool::BuildFile(),
  6. Поиск сообщения и / или полей с одним из Find… функции, применяемые на FileDescriptor пример.
  7. Вызвать функцию GetSourceLocation на экземпляре дескриптора сообщения / поля.
  8. Прочитайте комментарии через google::protobuf::SourceLocation::leading_comments а также google::protobuf::SourceLocation::trailing_comments,

Это кажется мне довольно сложным, поэтому у меня есть два дополнительных вопроса:

  1. Разве нет способа включить информацию об источнике без использования FileDescriptorSet?
  2. Можно ли "подключить" / установить 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).

Другие вопросы по тегам