
不久前,我感到困惑的是,基于protobuf和gRPC的,与Qt完全兼容的便利和简单的包装器和生成器还不够。 我碰到过很多文章,包括 关于包装器,但是在我看来,它们的使用甚至比现有的C ++ API还不实用。
关于gRPC和protobuf的一些知识
让我们模拟一个情况:您将要编写一个多平台项目,并且需要选择一个RPC框架与服务进行通信。 您总是可以自拔,说“我是我自己的框架”,但在我看来,我们正处在现成解决方案的时代。 这种解决方案之一是由一家知名公司长期提供给我们的。 我不假定要比较RPC框架,这不是本文的目的。 只是列出我喜欢的gRPC:
- 简洁明了的IDL
- 大量用于各种平台的发电机
- 生成的客户端/服务器代码,用于快速轻松地进行原型设计和编写测试应用程序
要点
由于Qt在类型反射方面做得很好,并且元信息的数量通常处于最高水平,因此意识到您需要自己的生成器来生成“纯” Qt代码,而无需散布第三方库。 因此,qtprotobufgen诞生了。
甲胎蛋白
qtprotobufgen是最简单的固有生成器,它基于libprotoc提供的API。 如果您想根据自己的需要制作类似的东西,我会作弊。
- 您只有一个插件类的入口点::: google :: protobuf ::编译器:: CodeGenerator,您需要从中继承
- 生成虚拟方法确定使用单独的.proto文件时的生成
- 当使用完整的.proto文件数组提供生成或依赖关系时,虚拟的GenerateAll方法确定生成
- 虚拟的HasGenerateAll方法本质上是先前版本中遗留下来的遗物。 返回真
我必须马上说,因为protobuf开发人员有现成的解决方案,所以不想从头开始编写自己的解析器/生成器。 但是,如果您愿意,您可以读取存在协议问题的二进制流,或者编写自己的原始文件解析器。
在开发过程中,以编译语言编写的生成器的一个重大缺点浮出水面:很难将生成和编译放在一个CMake堆栈中。 由于Qt会根据标头文件中声明的类的主体中具有Q_OBJECT宏的标头文件生成元对象信息,因此在配置阶段(读取cmake)有必要了解moc将为进一步代码生成提供的文件。 作为解决方案,我不得不求助于解释语言Go(Lang),该语言没有创建其他依赖项,并且可以很好地完成其工作,但是没有通过足够的测试。
生成器要遵守现有的协议规则,并且在编写本文时,不会引入任何其他生成选项:
protoc --plugin=protoc-gen-qtprotobuf=<path/to/bin>/qtprotobufgen --qtprotobuf_out=<output_dir> <protofile>.proto [--qtprotobuf_opt=out=<output_dir>]
为了简单易用,您可以使用专门准备的cmake例程来生成代码,并将其嵌入到cmake项目中。
更多细节...关于图书馆
在详细描述API方面,我没有多大意义。 那些希望的人可以
生成文档并阅读更多有关当前可用API的信息。
该项目分为2个逻辑部分qtprotobuf和qtgrpc。 从名称来看,我认为每个组件的目的都很明确。 我们尝试使使用尽可能方便,因为对于在系统中预先组装和安装的库,以及将子项目集成到cmake项目中,都有集成选项。
生成的代码完全
*导出到QML,这使得使用gRPC API更加容易。
使用方法
与项目集成并执行生成后,您将收到一组源文件,这些源文件随后将收集在静态库中并链接到您的二进制文件。 最近的更改排除了生成和原型静态注册的可能性。 因此,您需要注意他们在项目中的注册:
... #include <QtProtobufTypes> ... int main(int argc, char *argv[]) { QtProtobuf::registerProtoTypes(); ... // Qt }
在撰写本文时,没有用于注册为原型包生成的所有类型的单一方法,因此您需要为应用程序中使用的所有类型调用qRegisterProtobufType方法:
... qRegisterProtobufType<MyProtoType>(); ...
自述文件中描述了库和生成器的用法,并且该项目附带了几个示例。 对于那些根本不熟悉gRPC / protobuf的人,建议您阅读
官方文档对于开发人员
我们试图在开发过程中遵守TDD,并且不想偏离它。 正如我们的经验所示,TDD在重构或更新API时可以为您省钱,它有助于检测隐藏的问题。 因此,如果希望有所贡献,请准备编写单元,单元和功能测试。
*已知问题
当前存在许多与Qt相关的问题。 在我们的参与下或没有我们的参与下,其中一些已解决,但并非所有都包含在当前的Qt版本中。 主要的问题是qml代码无法访问某些基本的protobuf类型。 我认为对于QML中可用的类型集非常有限的人来说,这并不是什么秘密,部分原因是因为使用V8作为JS引擎。 试图使QML对自定义类型(例如,fixed32,sint32)更加友好的尝试失败了,但结果却解决了
问题的根源。 QtNetwork的当前实现也存在许多问题,但是Qt团队迅速解决了这些问题。
QTBUG-77852QTBUG-76303QTBUG-78310计划
当前的所有活动都与项目代码或Qt代码中的故障排除有关。 但是,与新功能相关的工作量很大:
转换为一对.h / .cpp文件以生成代码- GRPC服务器实施
回收gRPC凭证的API- 将生成的代码分发到目录中,并创建子项目插件,以分别加载生成的包和模块
Qmake整合CI实施
有一些积压,这些积压仍存储在其自己的项目存储库中。
除了结论以外,我还要感谢PVS-Studio的同志为OSS项目提供的密钥。 在他们的帮助下,他们在生成的代码中发现了一个相当关键的错误。
下载,查看项目并
在此处试用示例。