9 · 构建、注册与测试:大型 C++/Python 工程如何保持一致
Bazel、算子注册、kernel registry、生成 API 与测试矩阵
BUILD 文件是模块边界
TensorFlow 的 BUILD / *.bzl 不只是打包脚本,它们声明库、生成代码、平台选择、可见性和依赖图。根目录同时存在 MODULE.bazel 与 WORKSPACE,源码还通过 third_party 拉起 Eigen、absl、protobuf、XLA 等外部依赖;.bazelversion 把工具链版本固定为 7.7.0。
一个 op 的三份合同
REGISTER_OP("MatMul")
├─ shape/type/attr contract: tensorflow/core/ops/math_ops.cc
├─ generated wrapper: tensorflow/python/ops/gen_math_ops.py
└─ kernel: tensorflow/core/kernels/matmul_op*.ccREGISTER_OP 定义名字、输入输出类型、attrs、shape function 和文档。kernel 通过 REGISTER_KERNEL_BUILDER 按 op name、device、type constraint、label 注册。运行时先查 op definition,再查合适的 kernel registration;缺少任一合同都会在构图或执行时失败。
为什么 kernel 可以被替换
同一个 MatMul 可以有 CPU、GPU、oneDNN、quantized 或特殊 device 版本。registry key 通常包含 device type 和类型/属性约束,选择过程会处理优先级、label、版本和 attr mismatch。这个设计允许硬件后端独立增加实现,也意味着错误信息必须解释“找到 op 了,但没找到匹配 kernel”的区别。
生成 API 与兼容性
Python public API、op wrapper 和 API golden files 由 tensorflow/tools/api 等工具生成/检查。生成层减少手写重复,但把 build、Python export、protobuf schema 和文档签名绑在一起。新增 public symbol 不只改一个 __init__.py,还要考虑 API compatibility、类型 stub、文档和测试。
测试矩阵
源码测试至少覆盖:Python unit tests、C++ gtest、kernel tests、eager/graph dual tests、device-specific tests、distributed tests、API compatibility 和 build-only targets。测试失败定位时先分类:语义错误、设备缺少 kernel、非确定性/并发、构建依赖或生成文件不一致。
源码锚点
MODULE.bazel/WORKSPACE:仓库、工具链和依赖初始化。tensorflow/core/ops/:op definition 与 shape function。tensorflow/core/kernels/:CPU/通用 kernel。tensorflow/core/framework/op_kernel.h:kernel 接口与Compute。tensorflow/core/framework/op_kernel.cc:kernel registry lookup。tensorflow/tools/api/:API 生成/兼容性检查。tensorflow/python/下的*_test.py与tensorflow/core/**下的*_test.cc:分层测试样例。