如何在Bazel的py_library中依赖tiny-cuda-nn的CMake构建目标?
我尝试用Bazel封装tiny-cuda-nn作为其他项目的依赖,该项目是CMake项目但提供Python绑定,常规安装方式为执行以下pip命令:
pip install git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch
我已在WORKSPACE文件中通过new_git_repository拉取了tiny-cuda-nn仓库,配置如下:
load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") _ALL_CONTENT = """\ filegroup( name = "all_srcs", srcs = glob(["**"]), visibility = ["//visibility:public"], ) """ new_git_repository( name = "tinycudann_repo", branch = "master", build_file_content = _ALL_CONTENT, recursive_init_submodules = True, remote = "git@github.com:NVlabs/tiny-cuda-nn.git", )
在./third_party/tinycudann目录下的BUILD.bazel文件中,我定义了cmake目标built_and_installed_tinycudann和py_library目标tinycudann_py_lib,并将cmake目标作为py_library的依赖,配置如下:
load("@rules_python//python:pip.bzl", "compile_pip_requirements") # Update requirements based on requirements_lock.in compile_pip_requirements( name = "requirements_lock", src = "requirements_lock.in", requirements_txt = "requirements_lock.txt", ) load("@rules_python//python:defs.bzl", "py_library") load("@pip_deps_nerfstudio//:requirements.bzl", "requirement") # First, build tinycudann. load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") cmake( name = "built_and_installed_tinycudann", install = True, lib_source = "@tinycudann_repo//:all_srcs", out_binaries = [ "mlp_learning_an_image", "bench_image_ours", ], out_static_libs = [ "libtiny-cuda-nn.a", ], ) py_library( name = "tinycudann_py_lib", srcs = ["@tinycudann_repo//:all_srcs"], visibility = ["//visibility:public"], deps = [ ":built_and_installed_tinycudann", requirement("torch"), ], )
requirements_lock.in文件仅包含torch==2.4.0,requirements_lock.txt通过bazel run命令生成。预期其他Python脚本可通过依赖//third_party/tinycudann:tinycudann_py_lib来使用该库。
单独构建cmake目标时会正常编译(耗时约15分钟),但构建py_library仅需1秒,未触发CMake编译;下游引用该库的脚本报错:AttributeError: module 'tinycudann' has no attribute 'Encoding'。
我的核心疑问有两点:
- 为何py_library未触发其依赖的cmake目标构建?
- 即便能触发构建,py_library是否是使用该CMake构建项目的正确方式?
1. py_library未触发cmake构建的原因
Bazel的依赖触发逻辑是仅当目标实际依赖对方的输出文件时,才会触发依赖构建。你的py_library仅将built_and_installed_tinycudann列为deps,但srcs直接引用了原始仓库的未编译文件,没有关联cmake生成的任何产物(比如编译后的Python绑定模块)。Bazel分析后判定py_library不需要cmake目标的输出,因此跳过了构建流程。
简单来说:deps只是声明了逻辑依赖,但没有实际的文件依赖关系,Bazel的增量构建机制会忽略这种无输出关联的依赖。
2. 正确的构建方式:关联cmake生成的Python绑定
tiny-cuda-nn的Python绑定是编译生成的二进制扩展模块(如.so/.pyd文件),并非纯Python源码,因此不能直接用py_library引用原始仓库文件。需要调整构建流程,让Bazel识别并使用cmake生成的绑定产物:
步骤1:修改cmake目标,确保生成并安装Python绑定
tiny-cuda-nn的Python绑定在bindings/torch目录下生成,需在cmake配置中开启绑定构建,并指定安装路径:
cmake( name = "built_and_installed_tinycudann", install = True, lib_source = "@tinycudann_repo//:all_srcs", # 指定构建参数,开启Python绑定并关闭不必要的示例编译 cmake_options = [ "-DCMAKE_INSTALL_PREFIX=$(BINDIR)/install", "-DTINY_CUDA_NN_BUILD_PYTHON_BINDINGS=ON", "-DTINY_CUDA_NN_BUILD_EXAMPLES=OFF", ], # 声明输出的Python二进制模块(根据系统调整后缀,如Windows下为.pyd) out_shared_libs = [ "tinycudann/tinycudann.so", ], )
步骤2:用py_library引用cmake生成的绑定模块
不能直接使用原始仓库源码,需引用cmake安装后的Python模块目录,并将二进制文件加入data确保运行时可访问:
py_library( name = "tinycudann_py_lib", # 引用cmake生成的Python模块目录 srcs = [":built_and_installed_tinycudann"], # 将二进制扩展模块加入data,确保Bazel运行时将其放入Python的sys.path data = [":built_and_installed_tinycudann"], visibility = ["//visibility:public"], deps = [ requirement("torch"), ], )
关键说明
- tiny-cuda-nn的Python绑定是编译产物,原始仓库中没有可直接导入的纯Python模块,必须通过cmake构建后才能使用。
py_library的data属性必须包含二进制扩展模块,否则运行时Python无法找到该模块。
内容的提问来源于stack exchange,提问作者Chuck

