Rust项目如何将非Rust仓库声明为依赖以使用外部protobuf定义
解决方案
核心问题说明
Cargo的git依赖仅支持指向包含
Cargo.toml的合法Rust crate仓库,你引用的protobuf定义仓库没有Rust crate配置,因此直接声明为build-dependencies必然会触发找不到Cargo.toml的报错,该用法不符合Cargo的依赖设计规则。
推荐实现方案(满足依赖统一管理要求)
这套方案不需要修改外部protobuf仓库,所有配置集中在你的主仓库Cargo.toml中,无需额外维护子模块或独立crate:
- 第一步:配置
Cargo.toml
首先添加构建依赖,同时将protobuf仓库的版本信息写入自定义metadata区块统一管理:[build-dependencies] prost-build = "0.12" git2 = "0.18" # 用于拉取git仓库,也可以换成reqwest拉取zip包减少依赖体积 serde = { version = "1.0", features = ["derive"] } toml = "0.8" [package.metadata.protobuf-repo] git_url = "https://github.com/username/pbrepo" commit_hash = "fdefgd9" # 固定commit版本,保证构建可复现 proto_subpath = "proto" # proto文件在仓库中的根目录,按需修改 - 第二步:编写
build.rs构建脚本
脚本逻辑统一从Cargo.toml读取配置,自动拉取指定版本的protobuf仓库到Cargo管理的构建临时目录OUT_DIR中,再调用prost-build生成Rust代码:use std::env; use std::path::PathBuf; use git2::Repository; use prost_build::Config; use serde::Deserialize; use std::fs; #[derive(Deserialize)] struct Metadata { #[serde(rename = "protobuf-repo")] protobuf_repo: ProtobufRepoConfig, } #[derive(Deserialize)] struct ProtobufRepoConfig { git_url: String, commit_hash: String, proto_subpath: String, } fn main() { // 读取Cargo.toml配置 let cargo_toml_content = fs::read_to_string("Cargo.toml").unwrap(); let cargo_toml: toml::Value = toml::from_str(&cargo_toml_content).unwrap(); let metadata: Metadata = cargo_toml.get("package").unwrap().get("metadata").unwrap().clone().try_into().unwrap(); let proto_config = metadata.protobuf_repo; // 拉取protobuf仓库到构建临时目录 let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let repo_dir = out_dir.join("pbrepo"); if !repo_dir.exists() { let repo = Repository::clone(&proto_config.git_url, &repo_dir).unwrap(); let commit = repo.revparse_single(&proto_config.commit_hash).unwrap(); repo.checkout_tree(&commit, None).unwrap(); } // 编译proto文件生成Rust代码 let proto_root = repo_dir.join(proto_config.proto_subpath); let proto_files = fs::read_dir(&proto_root).unwrap() .filter_map(|e| e.ok()) .filter(|e| e.path().extension().unwrap_or_default() == "proto") .map(|e| e.path()) .collect::<Vec<_>>(); Config::new() .out_dir(&out_dir) .compile_protos(&proto_files, &[proto_root]) .unwrap(); } - 第三步:创建
src/common_protobuf/mod.rs引入生成代码,按需重导出
不需要手动生成代码到src目录污染源码仓库,直接引入Cargo构建目录中的生成文件即可:// 引入生成的所有protobuf Rust代码 include!(concat!(env!("OUT_DIR"), "/mod.rs")); // 按需重导出结构体到外部模块 pub use user::*; pub use order::*;
轻量替代方案
如果不想在构建脚本中引入git拉取的依赖,也可以使用git子模块将protobuf仓库放到主仓库的third_party/pbrepo路径下,仅需要修改build.rs直接读取本地子模块的proto文件即可,更新protobuf版本时执行git submodule update --remote即可,所有版本记录仍保存在主仓库中。
内容的提问来源于stack exchange,提问作者amustafa
相关产品推荐
相关产品推荐

