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

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

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

В официальной документации указано, что комментарии к .proto файлам можно читать:

  1. С помощью функции DebugStringWithOptions(), вызываемой сообщение или дескриптор.
  2. С помощью функции _3 _, вызванный дескриптором.

Я не могу получить комментарии, поэтому думаю, что делаю что-то совершенно не так, или эта функция еще не полностью реализована в буферах протокола.

Вот несколько фрагментов кода:

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.

Может ли кто-нибудь направить меня в правильном направлении и / или предоставить рабочий пример?

ИЗМЕНИТЬ 24 сентября 2015 г .:

После рассмотрения раздела Самоописывающиеся сообщения в официальной документации и тестировании много всего, мне кажется, я немного лучше разбираюсь в дескрипторах protobuf.

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

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

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

  1. Вызвать протокол для файла 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 с конкретным классом / экземпляром сообщения, поскольку это резко упростит ситуацию?

РЕДАКТИРОВАТЬ 25 сентября 2015 г .: Под God Class я имею в виду, что класс Message и / или классы дескрипторов предлагают общедоступные функции, которые более или менее бесполезны, поскольку они не предоставляют информация при использовании клиентом. Возьмем, к примеру, «нормальное» сообщение: сгенерированный код не содержит информацию об исходном комментарии, поэтому метод GetSourceLocation во всех классах дескрипторов (например, Descriptor и FieldDescriptor) совершенно бесполезен. С логической точки зрения должны быть предоставлены отдельные экземпляры DescriptorLite и FieldDescriptorLite при работе с сообщениями и Descriptor и FieldDescriptor при работе с информацией из FileDescriptorSet (источником которого обычно является файл .desc, сгенерированный из файла .proto). Тогда [...]Lite класс будет родительским классом «нормального» класса. Аргумент о том, что protoc, возможно, никогда не будет включать комментарии к источникам, подчеркивает мою точку зрения.

Под «соединением» я имею в виду функцию API, которая обновляет информацию дескриптора в сообщении с помощью информации дескриптора из файла .desc (который всегда является надмножеством дескрипторов, предоставленных сообщением, если я правильно понял).


person Florian Wolters    schedule 23.09.2015    source источник
comment
Возможно ли, что это связано с компилятором протокольных буферов protoc? Я только что наткнулся на protoc аргументы -o и --include_source_info. Нужно ли мне создавать FileDescriptorSet, чтобы получать комментарии?   -  person Florian Wolters    schedule 23.09.2015


Ответы (1)


Похоже, вы в основном в этом разобрались.

Вы углубляетесь в API-интерфейсы внутри компилятора протокола, которые на самом деле не были предназначены для публичного использования. Это усложняется, потому что никто не написал вспомогательный уровень для упрощения, потому что не многие люди используют эти функции.

Я не совсем понимаю, что вы имеете в виду, говоря Message быть "классом Бога". Message - это просто абстрактный интерфейс для экземпляра protobuf. Дескрипторы описывают типы экземпляров protobuf. Message::getDescriptor() возвращает тип сообщения, но помимо этого между этими API нет прямой связи ...

Нет ли способа включить исходную информацию без использования FileDescriptorSet?

Комментарии намеренно удаляются из дескрипторов, встроенных в сгенерированный код, поэтому вам нужно запустить синтаксический анализатор отдельно, сгенерировать набор дескрипторов и использовать его динамически.

Можно ли «связать» / установить FileDescriptorSet с конкретным классом / экземпляром сообщения, поскольку это резко упростит ситуацию?

Вы имеете в виду, что хотите, чтобы Message :: getDescriptor () возвращал дескриптор, который включает данные комментария из исходного файла? Для этого потребуется, чтобы данные комментария были встроены в сгенерированный код, что было бы тривиально для protoc для реализации (в настоящее время он намеренно удаляет их, поэтому ему просто нужно не этого делать), но потенциально может раздуваться - y и опасно (может раскрыть секреты для людей, поставляющих двоичные файлы с закрытым исходным кодом, созданные с помощью protobufs).

person Kenton Varda    schedule 25.09.2015
comment
Спасибо за ваш комментарий и объяснение! Я снова обновил свой вопрос для уточнения. Позже добавлю рабочий пример, может, тогда кто-нибудь его пересмотрит. - person Florian Wolters; 25.09.2015
comment
@FlorianWolters Спасибо за разъяснения. Однако я не согласен с предложением: расположение источников - это неясная, редко используемая часть интерфейса дескриптора. Нет смысла усложнять иерархию классов специально, чтобы различать дескрипторы с информацией об источнике и без нее. Кроме того, некоторые подклассы сообщений (например, DynamicMessage) действительно могут иметь исходную информацию в своих дескрипторах. (Конечно, я больше не работаю над protobufs, так что это ни в коем случае не мое.) - person Kenton Varda; 30.09.2015