You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 01:36:08