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

相对路径在cargo build生效但cargo publish失效的问题求助

解决Cargo Publish时Prost无法找到Proto文件的问题

问题场景

项目结构如下:

root/
  - proto/
    - my.proto
  - python/
  - rust/
    - Cargo.toml
    - build.rs
    - ...

使用prost生成Rust代码的build.rs代码如下:

use std::io::Result;
fn main() -> Result<()> {
    prost_build::compile_protos(
        // 待编译文件
        &["my.proto"],
        // protoc的包含目录
        &["../proto/"])?;
    Ok(())
}

cargo build执行正常,但cargo publish时失败,protoc报错:

ignoring ../proto/ since it does not exist

失败原因

cargo build是在当前rust目录下执行的,相对路径../proto/能正确指向root目录下的proto文件夹。但cargo publish执行时,Cargo会先把当前Rust包的代码复制到target目录下的临时子文件夹中做打包验证,此时临时目录的上级目录不是root,而是target下的其他目录,所以../proto/这个相对路径就找不到对应的目录了。

更关键的是,默认情况下cargo publish只会打包当前Rust包目录(rust/)下的文件,root/proto/里的内容不会被包含到发布的包中——就算路径问题解决了,发布后的包也会缺失proto文件,导致下游依赖编译失败。

解决方案

方案1:将proto文件纳入Rust包的源码范围(推荐用于发布)

  1. 在rust目录下创建proto子目录,把root/proto/下的my.proto复制过来(不推荐软链,避免跨目录依赖问题),调整后的项目结构:
root/
  - proto/
    - my.proto
  - python/
  - rust/
    - proto/
      - my.proto
    - Cargo.toml
    - build.rs
    - ...
  1. 修改build.rs中的路径配置:
use std::io::Result;
fn main() -> Result<()> {
    prost_build::compile_protos(
        &["proto/my.proto"],
        &["."]
    )?;
    Ok(())
}
  1. 在Cargo.toml中添加include配置,确保publish时能把proto文件打包进去:
[package]
# 保留原有配置...
include = ["src/**/*", "proto/**/*", "build.rs", "Cargo.toml"]

方案2:使用绝对路径临时解决本地publish验证(不推荐正式发布)

如果不想移动proto文件,可以在build.rs中通过env!("CARGO_MANIFEST_DIR")获取当前包的根目录,拼接出proto文件的绝对路径:

use std::io::Result;
use std::path::Path;

fn main() -> Result<()> {
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    let proto_path = Path::new(manifest_dir).join("../proto/my.proto");
    let include_dir = Path::new(manifest_dir).join("../proto/");
    
    prost_build::compile_protos(
        &[proto_path.to_str().unwrap()],
        &[include_dir.to_str().unwrap()]
    )?;
    Ok(())
}

注意:这个方案只能解决本地publish时的路径验证问题,发布到crates.io后的包仍然会缺失proto文件,下游依赖编译时会失败,仅适合本地调试使用。

方案3:将proto文件作为独立模块共享(适合多语言场景)

如果需要Python、Rust等多语言共享proto定义,可以把proto文件放到单独的git仓库,在rust目录中通过git子模块引入;或者将proto发布为单独的Crate,让Rust包通过依赖的方式获取proto文件,彻底避免路径问题。

关于相对路径的合理性

本地开发中使用跨目录的相对路径是可行的,但绝对不适合用于需要发布的Cargo包。因为Cargo发布的包只能包含当前包目录下的文件,跨目录的相对路径在打包验证和下游依赖编译时都会失效。正式发布的包应该尽量将依赖的资源文件放在包目录内部,或者通过依赖管理的方式引入。

内容的提问来源于stack exchange,提问作者Achim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:55:24