如何在tonic_build中跨Crate导入公共common.proto文件?
解决方案
方法一:调整编译路径与导入语句
问题核心是protoc编译时的搜索路径和VSCode的路径逻辑不一致——你当前的build.rs只把players crate下的src/proto设为搜索目录,导致找不到工作区根目录下的common.proto。
1. 修改proto导入语句
将players.proto中的导入路径改为基于工作区根目录的相对路径:
syntax = "proto3"; package players; import "google/protobuf/timestamp.proto"; // 改用基于工作区根目录的路径 import "common/src/common.proto";
2. 更新build.rs的搜索路径
在compile方法的第二个参数中,添加工作区根目录的相对路径(从players crate根目录到工作区根目录是../../../):
fn main() -> Result<(), Box<dyn std::error::Error>> { tonic_build::configure() .out_dir("src/proto") .compile( &["src/proto/players.proto"], &["src/proto", "../../../"], // 加入工作区根目录作为protoc搜索路径 )?; Ok(()) }
3. 同步VSCode识别路径(可选)
为了让VSCode的proto插件也能正确识别导入路径,在工作区的.vscode/settings.json中添加:
{ "protoc.options": ["--proto_path=${workspaceFolder}"] }
方法二:将common封装为独立依赖Crate(推荐)
重复在多个crate中管理proto导入容易出错,更优雅的方式是把common做成独立crate,编译自身proto后供其他crate依赖:
1. 配置common crate的build.rs
在src/common/build.rs中编写编译逻辑:
fn main() -> Result<(), Box<dyn std::error::Error>> { tonic_build::configure() .out_dir("src/proto") // 生成的rust代码放在src/proto目录 .compile( &["src/common.proto"], &["src"], )?; Ok(()) }
2. 声明common crate的依赖
在src/common/Cargo.toml中添加必要依赖:
[dependencies] tonic = "0.9" prost = "0.12" [build-dependencies] tonic-build = "0.9"
3. 其他crate依赖common
在players/Cargo.toml中添加common crate的依赖:
[dependencies] common = { path = "../../common" } tonic = "0.9" prost = "0.12"
这样players crate中无需再处理common.proto的导入,直接通过rust模块引用:
use common::proto::Pagination; use common::proto::Page;
这种方式避免了重复编译proto,也简化了跨crate的类型共享,更符合Cargo工作区的设计理念。
内容的提问来源于stack exchange,提问作者Fred Hors
相关产品推荐
相关产品推荐

