使用Bazel构建依赖C库的Rust crate遇CMake报错:原因与解决
Bazel构建依赖C库的Rust Crate时CMake找不到的问题解决
问题描述
尝试用Bazel的rust_rules(尤其是crate_universe规则)构建依赖rdkafka和paho-mqtt的Rust crate,Cargo.toml依赖如下:
[dependencies] serde = { version = "1.0.163", features = ["derive"] } chrono = { version = "0.4.26", features = ["serde"] } uuid = { version = "1.3.3", features = ["v7", "serde"] } rdkafka = { version = "0.31", features = ["cmake-build"] } paho-mqtt = { version = "0.11" }
Bazel WORKSPACE配置:
crates_repository( name = "crate_index", cargo_lockfile = "//my-crate:Cargo.lock", lockfile = "//my-crate:Cargo.Bazel.lock", manifests = ["//my-crate:Cargo.toml"], annotations = { "uuid": [crate.annotation( rustc_flags = ["--cfg=uuid_unstable"], )], }, ) load("@crate_index//:defs.bzl", "crate_repositories") crate_repositories()
BUILD文件配置:
load("@crate_index//:defs.bzl", "all_crate_deps") load("@rules_rust//rust:defs.bzl", "rust_library") rust_library( name = "my-crate", srcs = glob(["src/**/*.rs"]), deps = all_crate_deps( normal = True, ), )
运行bazel build //my-crate时触发错误:
--stderr: Building and linking librdkafka statically CMake Error: Could not find CMAKE_ROOT !!! CMake has most likely not been installed correctly. Modules directory not found in CMake Error: Error executing cmake::LoadCache(). Aborting. thread 'main' panicked at ' command did not execute successfully, got: exit status: 1
该错误同时出现在rdkafka和paho-mqtt构建过程中,移除rdkafka的cmake-build特性后问题依旧。
已尝试操作
cargo build构建成功,排除系统CMake安装问题- 尝试
export CMAKE_ROOT=/path、Bazel运行参数--action_env=CMAKE_ROOT=/path及use_default_shell_env=True,均未解决
补充信息
- 操作系统:Arch
- Bazel版本:6.2.1
- CMake版本:3.26.4
- Rust工具链配置:
rust_register_toolchains( edition = "2021", versions = [ "1.70.0" ], )
报错原因
Bazel默认启用沙箱构建环境,会隔离大部分系统环境变量和路径。即使系统已安装CMake,rdkafka和paho-mqtt的build.rs在沙箱中无法访问系统的CMake可执行文件及相关环境变量(比如CMAKE_ROOT),导致CMake初始化失败。
另外,crate_universe默认不会自动处理依赖系统C库的Rust crate,需要显式配置让构建过程能找到系统预编译库,或引入Bazel的CMake工具链。
解决方法(避免编译librdkafka)
方案1:改用系统预编译的C库
修改Cargo.toml,让rdkafka和paho-mqtt直接链接系统已安装的库,跳过源码编译:
[dependencies] # 其他依赖保持不变 rdkafka = { version = "0.31", features = ["system-librdkafka"] } # 替换cmake-build为system-librdkafka paho-mqtt = { version = "0.11", features = ["system"] } # 启用system特性链接系统库
然后更新Bazel的crates_repository配置,添加注解让build.rs能找到系统库路径:
crates_repository( name = "crate_index", cargo_lockfile = "//my-crate:Cargo.lock", lockfile = "//my-crate:Cargo.Bazel.lock", manifests = ["//my-crate:Cargo.toml"], annotations = { "uuid": [crate.annotation( rustc_flags = ["--cfg=uuid_unstable"], )], # 给rdkafka传递系统库链接参数 "rdkafka": [crate.annotation( build_env = { "RDKAFKA_LIB_DIR": "/usr/lib", # 根据Arch系统的librdkafka路径调整 "RDKAFKA_INCLUDE_DIR": "/usr/include", }, )], # 给paho-mqtt传递系统库链接参数 "paho-mqtt": [crate.annotation( build_env = { "PAHO_MQTT_C_LIB_DIR": "/usr/lib", "PAHO_MQTT_C_INCLUDE_DIR": "/usr/include", }, )], }, )
最后重新生成Bazel锁文件:
bazel run @rules_rust//crate_universe:generate_lockfile -- --manifest-path=my-crate/Cargo.toml --output=my-crate/Cargo.Bazel.lock
方案2:让Bazel沙箱访问系统CMake(若需编译源码)
如果必须编译librdkafka源码,需要在Bazel中引入CMake工具链,并允许构建过程访问系统环境:
- 在WORKSPACE中加载Bazel的CMake规则:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "rules_foreign_cc", sha256 = "d5a2ad2b08c7d38f996907a00540741c368f224a6b51d4f37d15b555059e4405", url = "https://github.com/bazelbuild/rules_foreign_cc/releases/download/0.9.0/rules_foreign_cc-0.9.0.tar.gz", ) load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") rules_foreign_cc_dependencies()
- 在crates_repository中添加注解,给rdkafka和paho-mqtt传递CMake路径:
crates_repository( # 其他配置不变 annotations = { # 其他注解不变 "rdkafka": [crate.annotation( build_env = { "CMAKE": "/usr/bin/cmake", # 系统CMake路径 }, )], "paho-mqtt": [crate.annotation( build_env = { "CMAKE": "/usr/bin/cmake", }, )], }, )
同时构建时需要允许Bazel访问系统环境:
bazel build //my-crate --action_env=PATH=/usr/bin:$PATH --use_default_shell_env
此方案会编译librdkafka源码,不符合简化配置需求,优先推荐方案1。
内容的提问来源于stack exchange,提问作者dloez
相关产品推荐
相关产品推荐

