ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Nanopb Bazel 构建集成指南:在 Flipper Zero 固件仓库中使用 cc_nanopb_proto_library

Nanopb Bazel 构建集成指南:在 Flipper Zero 固件仓库中使用 cc_nanopb_proto_library Nanopb Bazel 构建集成指南在 Flipper Zero 固件仓库中使用 cc_nanopb_proto_library【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware本篇技术指南以 nanopb 官方 Bazel 构建文档为骨架结合本仓库flipperzero-firmware内lib/nanopb的实际源码与构建规则实现系统讲解如何将 nanopb 的 protobuf 编解码能力集成进 Bazel 构建系统。读完本文你将掌握完整的 WORKSPACE 接入流程、cc_nanopb_proto_library规则的声明方式、自定义.options配置文件的使用方法以及 nanopb 插件与规则底层的实现原理可直接在自己的 Bazel 工程中复制落地。Nanopb 与 Bazel 构建简介Nanopb 是一套面向嵌入式系统设计的 Protocol Buffers 实现以极小内存占用著称非常适合微控制器等资源受限场景。Bazel 构建系统则以其可复现、增量编译快、依赖分析精确著称。Nanopb 为 Bazel 提供了一组官方插件规则使得.proto文件可以在构建期自动生成.pb.c/.pb.h并编译为 C 库无需手动运行protoc。在本仓库中nanopb 位于 lib/nanopb其核心库由 pb_common.c、pb_decode.c、pb_encode.c 三个源文件构成而 Bazel 集成所需的全部规则文件集中在 lib/nanopb/extra/bazel 目录下。WORKSPACE 接入三步完成依赖声明要在自己的 Bazel 工程中使用 nanopb 规则首先需要在WORKSPACE文件中完成仓库拉取与依赖初始化。官方文档给出了完整的接入模板# WORKSPACE git_repository( name com_github_nanopb_nanopb, remote https://github.com/nanopb/nanopb.git commit TODO:Enter your desired commit, ) load(com_github_nanopb_nanopb//extra/bazel:nanopb_deps.bzl, nanopb_deps) nanopb_deps() load(com_github_nanopb_nanopb//extra/bazel:python_deps.bzl, nanopb_python_deps) nanopb_python_deps() load(com_github_nanopb_nanopb//extra/bazel:nanopb_workspace.bzl, nanopb_workspace) nanopb_workspace()这三步的职责分工清晰可以从仓库源码逐一印证nanopb_deps()声明 nanopb 规则所依赖的第三方 Bazel 规则集。查看 lib/nanopb/extra/bazel/nanopb_deps.bzl 可以看到它通过http_archive分别拉取了rules_proto4.0.0、rules_python0.9.0和rules_proto_grpc4.4.0并附带固定了 SHA-256 校验值保证依赖版本的可复现性。其中rules_proto_grpc提供生成规则所需的proto_compile、ProtoPluginInfo、filter_files等基础设施。nanopb_python_deps()通过pip_parse建立名为nanopb_pypi的 Python 依赖仓库。其依赖锁定文件位于 lib/nanopb/extra/requirements_lock.txt核心依赖是grpcio-tools——nanopb 的代码生成器正是基于 protoc 插件机制实现的。该函数还接受可选的interpreter参数用于指定自定义 Python 解释器。nanopb_workspace()真正安装上述依赖并注册 toolchain。从 lib/nanopb/extra/bazel/nanopb_workspace.bzl 的实现看它依次调用install_deps()、rules_proto_grpc_toolchains()、rules_proto_grpc_repos()、rules_proto_dependencies()和rules_proto_toolchains()即完成 pip 依赖安装与 protobuf 编译工具链的注册。注意官方示例使用git_repository拉取 nanopb 主仓库实际使用时需要把TODO:Enter your desired commit替换为你选定版本的 commit 哈希也可以改用http_archive 发布 tarball 的方式获得更稳定的缓存。BUILD.bazel 用法从 proto_library 到 cc_nanopb_proto_library完成 WORKSPACE 配置后即可在目标目录的BUILD.bazel中声明构建目标。cc_nanopb_proto_library的使用方式与 Bazel 原生cc_proto_library高度类似官方文档给出了完整示例# BUILD.bazel load(com_github_nanopb_nanopb//extra/bazel:nanopb_cc_proto_library.bzl, nanopb_cc_proto_library) # Your native proto_library. proto_library( name descriptor, srcs [ generator/proto/google/protobuf/descriptor.proto, ], ) # Generated library. cc_nanopb_proto_library( name descriptor_nanopb, protos [:descriptor], visibility [//visibility:private], ) # Depend directly on the generated code using a cc_library. cc_library( name uses_generated_descriptors, deps [:descriptor_nanopb], hdrs [my_header.h], )整个链路分三层proto_libraryBazel 原生规则负责描述.proto源文件集合作为生成规则的输入cc_nanopb_proto_library核心生成规则自动调用 nanopb 的 protoc 插件产出 C 源码并打包成cc_librarycc_library业务代码直接通过deps依赖生成的库即可在头文件中#include生成的.pb.h并使用 nanopb API。这种分层结构与仓库内的真实用法完全一致。在 lib/nanopb/BUILD.bazel 中官方自测目标正是这样构建的descriptor与nanopb_proto两个proto_library被组合为测试目标而all_types_proto则配合all_types.options生成了all_types_nanopb库并由bazel_options_support这个cc_test进行编译期验证见 lib/nanopb/tests/bazel_options_support/bazel_options_support.cc。自定义 options 文件通过 nanopb_options_files 控制生成行为nanopb 允许通过.options文件对消息字段的编解码行为做精细控制如指定字段最大长度、是否使用固定数组等。在 Bazel 规则中这一能力通过nanopb_options_files参数暴露# Generated library with options. cc_nanopb_proto_library( name descriptor_nanopb, protos [:descriptor], nanopb_options_files [descriptor.options], visibility [//visibility:private], )该参数接受一个.options文件标签列表其底层实现可以从 lib/nanopb/extra/bazel/nanopb_cc_proto_library.bzl 的规则属性定义中印证nanopb_proto_compile_attrs dict( nanopb_options_files attr.label_list( allow_files [.options], doc An optional list of additional nanopb options files to apply, ), **proto_compile_attrs, )在cc_nanopb_proto_compile_impl实现函数中每个 options 文件都会被转换为 protoc 插件参数传递给 nanopb 生成器for options_target in ctx.attr.nanopb_options_files: for options_file in options_target.files.to_list(): extra_protoc_args extra_protoc_args [ --nanopb_plugin_opt-f{}.format(options_file.path)] extra_protoc_files extra_protoc_files [options_file]即每个.options文件对应一个--nanopb_plugin_opt-f路径参数同时该文件也会作为 protoc 的额外输入文件extra_protoc_files参与生成。这意味着nanopb_options_files是可选参数不提供时 nanopb 仍会以默认行为生成代码可以提供多个options 文件插件会依次应用options 文件路径必须能被 protoc 访问到规则已自动将其加入输入文件集合无需手工exports_files。生成规则实现拆解cc_nanopb_proto_library 背后发生了什么cc_nanopb_proto_library并非一个单一的底层 rule而是对编译、过滤、链接三步的封装这在 lib/nanopb/extra/bazel/nanopb_cc_proto_library.bzl 的函数体中有完整呈现编译内部创建名为name_pb的cc_nanopb_proto_compile目标该目标通过proto_compile执行 protoc默认插件为com_github_nanopb_nanopb//:nanopb_plugin过滤分别用filter_files按.c和.h扩展名把生成产物拆成源文件集合与头文件集合链接最终组装一个cc_library自动把com_github_nanopb_nanopb//:nanopb即 nanopb 运行时库加入deps并将生成头文件目录加入includes。值得关注的是该规则透传了大量原生cc_library支持的参数——copts、defines、local_defines、include_prefix、strip_include_prefix、linkopts、alwayslink、visibility、tags等因此可以在调用处直接控制生成库的编译选项与可见性无需二次包装。插件与运行时nanopb_plugin 与 nanopb 库的定义生成链路的最后一环是 protoc 插件与运行时库二者都在 lib/nanopb/BUILD.bazel 中定义//:nanopb运行时cc_library由pb_common.c、pb_decode.c、pb_encode.c及其对应头文件组成是链接阶段自动注入的依赖//:protoc-gen-nanopbpy_binary形式的生成器源码来自generator/目录的全部 Python 文件依赖grpcio-tools并打包了生成器所需的.proto定义//:nanopb_pluginproto_plugin声明内置--library-include-formatquote插件选项使生成的代码以引号形式 include nanopb 头文件声明输出为{protopath}.pb.h与{protopath}.pb.c两个文件。插件声明中值得注意的separate_options_flag True意味着每个 options 文件对应的-f参数是作为独立的插件参数传递的——这与前文cc_nanopb_proto_compile_impl中逐个拼接--nanopb_plugin_opt-fpath的实现正好呼应。版本维护requirements 锁定与更新nanopb 的 Bazel 集成将 Python 侧依赖收敛在pip_parse管理的锁定文件中。当前仓库的锁文件 lib/nanopb/extra/requirements_lock.txt 由pip-compile基于 Python 3.9 生成锁定了grpcio1.53.0其输入清单 lib/nanopb/extra/requirements.txt 仅声明了grpcio-tools1.51.3。两者版本不直接相同属于正常现象——grpcio-tools的依赖解析会拉取匹配的grpcio运行时。如需升级依赖仓库在 lib/nanopb/BUILD.bazel 末尾提供了一个compile_pip_requirements目标运行bazel run //:requirements.update即可重新生成锁文件这也是 requirements_lock.txt 头部注释给出的官方升级方式。常见问题与最佳实践必须遵循 WORKSPACE 三步顺序nanopb_deps()负责拉取rules_proto_grpc等规则集nanopb_python_deps()建立 pip 依赖nanopb_workspace()执行安装跳过任一步都会导致后续load失败。nanopb_options_files只接受.options文件规则属性通过allow_files [.options]做了约束传入其他扩展名会触发分析期错误。生成库默认私有可见性官方示例与仓库自测目标均使用visibility [//visibility:private]建议将生成的中间库设为私有、由上层cc_library对外暴露保持依赖边界清晰。proto 文件建议使用原生proto_library描述这保证了与 Bazel 生态其他 proto 规则如 gRPC的互操作也是 nanopb 官方推荐的做法。不需要手动运行 protoccc_nanopb_proto_library在构建期自动完成代码生成、编译与链接最终产物是可直接被deps引用的cc_library。小结Nanopb 的 Bazel 集成由三个.bzl文件nanopb_deps.bzl、python_deps.bzl、nanopb_workspace.bzl提供仓库级依赖管理由 nanopb_cc_proto_library.bzl 提供规则实现最终由根目录 BUILD.bazel 定义插件与运行时库。整个链路与官方文档中的三步接入、双层 BUILD 声明、options 文件传参一一对应既可直接照抄使用也可作为理解 Bazel proto 生态的参考样板。【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表