
Há não muito tempo, fiquei intrigado com o fato de não existirem invólucros e geradores simples e convenientes e simples para protobuf e gRPC, baseados e totalmente compatíveis com o Qt. Me deparei com artigos, incluindo aqui sobre wrappers, mas seu uso me pareceu muito menos prático do que a API C ++ existente.
Um pouco sobre gRPC e protobuf
Vamos simular uma situação: você escreverá um projeto de plataforma múltipla e precisará escolher uma estrutura RPC para se comunicar com seus serviços. Você sempre pode dar um soco no peito e dizer "Eu sou o meu próprio quadro", mas parece-me que estamos vivendo uma era de soluções prontas. Uma dessas soluções nos foi apresentada por uma empresa conhecida por um longo tempo. Não presumo comparar estruturas RPC, este não é o objetivo deste artigo. Apenas para listar o que eu gosto no gRPC:
- IDL conciso e claro
- A presença de um grande número de geradores para várias plataformas
- Código cliente / servidor gerado para aplicações de teste de gravação e prototipagem rápidas e fáceis
Ao ponto
Devido ao fato de o Qt estar se saindo muito bem com a reflexão de tipos e a quantidade de meta-informações geralmente estar no nível mais alto, chegou-se à conclusão de que você precisa de seu próprio gerador que gere código Qt "puro", sem intercalar bibliotecas de terceiros. Então, qtprotobufgen nasceu.
qtprotobufgen
qtprotobufgen é o gerador inerentemente mais simples, baseado na API fornecida pelo libprotoc. Caso você queira fazer algo assim para suas necessidades, deixarei um pouco de trapaça.
- Você tem um único ponto de entrada para a classe do plugin :: google :: protobuf :: compiler :: CodeGenerator, da qual você precisa herdar
- O método virtual Generate determina a geração ao trabalhar com um arquivo .proto separado
- O método virtual GenerateAll determina a geração ao trabalhar com uma matriz completa de arquivos .proto fornecidos para geração ou dependência
- O método virtual HasGenerateAll é essencialmente uma relíquia sobrevivente de versões anteriores. Return true
Devo dizer imediatamente que não havia desejo de escrever meu próprio analisador / gerador do zero, pois existe uma solução pronta dos desenvolvedores do protobuf. Mas, se desejar, você pode ler o fluxo binário que protoc emite ou escrever seu próprio analisador de arquivos proto.
Durante o desenvolvimento, surgiu uma desvantagem significativa de um gerador escrito em uma linguagem compilada: era difícil colocar a geração e a compilação em uma pilha do CMake. Devido ao fato de o Qt gerar informações de metaobjetos, com base em arquivos de cabeçalho com a macro Q_OBJECT no corpo das classes declaradas no arquivo de cabeçalho, é necessário, no estágio de configuração (leia cmake), ter uma idéia dos arquivos que o moc fornecerá para a geração de código adicional. Como solução, tive que recorrer à linguagem interpretada Go (Lang), que não criou dependências adicionais e fez seu trabalho perfeitamente, mas não passou em testes suficientes.
O gerador está sujeito às regras protoc existentes e, no momento da redação deste documento, não introduz nenhuma opção adicional de geração:
protoc --plugin=protoc-gen-qtprotobuf=<path/to/bin>/qtprotobufgen --qtprotobuf_out=<output_dir> <protofile>.proto [--qtprotobuf_opt=out=<output_dir>]
Para simplificar e facilitar o uso, você pode usar rotinas cmake especialmente preparadas para gerar código e incorporá-las em um projeto cmake.
Mais detalhes ...Sobre bibliotecas
Não vejo muito sentido em descrever a API em detalhes. Quem desejar pode
gerar documentação e ler um pouco mais sobre a API atualmente disponível.
O projeto é dividido em 2 partes lógicas qtprotobuf e qtgrpc. Pelos nomes, acho que o objetivo de cada componente é claro. Tentamos tornar o uso o mais conveniente possível, porque existem opções de integração com a biblioteca pré-montada e instalada no sistema e a integração do subprojeto no seu projeto cmake.
O código gerado é
* exportado completamente para QML, o que facilita muito o trabalho com a API gRPC.
Use
Após a integração com o projeto e a execução da geração, você receberá um conjunto de arquivos de origem, que posteriormente serão coletados em uma biblioteca estática e vinculados ao seu arquivo binário. Mudanças recentes excluíram a possibilidade de registro estático dos tipos gerados e protótipos. Portanto, você precisa cuidar do registro deles no projeto:
... #include <QtProtobufTypes> ... int main(int argc, char *argv[]) { QtProtobuf::registerProtoTypes(); ... // Qt }
No momento da redação deste artigo, não havia um método único para registrar todos os tipos gerados para um proto-pacote, portanto, você precisa chamar o método qRegisterProtobufType para todos os tipos usados no aplicativo:
... qRegisterProtobufType<MyProtoType>(); ...
O uso de bibliotecas e um gerador é descrito em README, e alguns exemplos acompanham o projeto. Para aqueles que não estão familiarizados com o gRPC / protobuf, sugiro que você leia a
documentação oficialPara desenvolvedores
Tentamos aderir ao TDD durante o desenvolvimento e não queremos nos afastar dele. Como nossa experiência demonstrou, o TDD economiza você ao refatorar ou atualizar a API, ajudando a detectar problemas ocultos. Portanto, se houver um desejo de contribuir, esteja preparado para escrever unidades, testes unitários e funcionais.
* Problemas conhecidos
Atualmente, existem vários problemas relacionados ao Qt. Alguns deles foram resolvidos, com ou sem a nossa participação, mas nem todos foram incluídos nos lançamentos atuais do Qt. O principal é a inacessibilidade de alguns tipos básicos de protobuf do código qml. Acho que não é segredo para ninguém que o conjunto de tipos disponíveis na QML é muito limitado, em parte devido ao uso da V8 como um mecanismo JS. Uma tentativa de tornar a QML um pouco mais amigável para tipos personalizados (por exemplo, fixed32, sint32) falhou, mas acabou por corrigir a origem do
problema . A implementação atual do QtNetwork também apresenta vários problemas, mas a equipe do Qt os corrige rapidamente.
QTBUG-77852QTBUG-76303QTBUG-78310Planos
Todas as atividades atuais estão relacionadas à solução de problemas no código do projeto ou no código Qt. Mas há uma quantidade bastante grande de trabalho associada à nova funcionalidade:
Transição para um único par de arquivos .h / .cpp para o código gerado- Implementação do servidor GRPC
API de reciclagem para credenciais de gRPC- Distribuição do código gerado nos diretórios e criação de plug-ins de subprojetos para carregamento separado de pacotes e módulos gerados
Integração QmakeImplementação de IC
Há alguma lista de pendências, que ainda é armazenada em seu próprio repositório de projetos.
Em vez de uma conclusão, gostaria de agradecer aos camaradas do PVS-Studio pela chave fornecida para os projetos de OSS. Com a ajuda deles, eles encontraram um bug bastante crítico no código gerado.
Faça o download, veja o projeto e brinque com exemplos
aqui .