Rust项目中neoeinstein-prost生成protobuf代码的规范存放与引用咨询
我在Rust项目中使用neoeinstein-prost buf插件生成protobuf代码,插件本身符合需求,但不确定生成的.rs文件的惯用存放位置、引用方式,以及这种场景是否需要用到工作区(当前项目未使用工作区)。我自己有两个备选方案,想知道是否符合惯例:
我的两个备选方案
方案1
优点:生成代码与手写代码物理分离,边界清晰;缺点:需要使用跨目录的#[path]指令,路径写法繁琐。
- examples (依赖lib) - gen |- src | |- my_model.v1.rs | |- my_model.v1.serde.rs (被my_model.v1.rs通过!include引入) - proto |- my_model | |- v1 | | |- my_model.proto - src |- main.rs (依赖lib) |- lib | |- lib.rs (通过#[path = "../../gen/src/my_model.v1.rs"]导出"model"模块)
方案2
优点:所有库代码(手写/生成)都在src目录下,封装统一;缺点:生成代码位置不直观,查找麻烦。
- examples (依赖lib) - proto |- my_model | |- v1 | | |- my_model.proto - src |- main.rs (依赖lib) |- lib | |- lib.rs (通过#[path = "gen/src/my_model.v1.rs"]导出"model"模块) | |- gen | | |- src (多余层级?) | | | |- my_model.v1.rs | | | |- my_model.v1.serde.rs (被my_model.v1.rs通过!include引入)
惯用方案与建议
1. 存放位置的惯例
Rust社区最常用的做法是将生成代码放在项目根目录的独立目录下,比如gen、proto-gen或prost-gen,和src、proto同级。这种方式的核心是把自动生成代码与手写代码物理隔离,避免生成文件污染手写源码目录,同时方便用.gitignore直接忽略整个生成目录(仅需添加/gen/)。
不推荐方案2的做法——把生成代码放在src内部,因为自动生成的代码会被插件频繁覆盖,和手写代码混放容易误操作,也不符合“源码目录只放人工维护代码”的惯例。
2. 引用方式的优化
你当前用#[path]硬编码路径的方式不够优雅,更规范的做法是把生成代码做成本地依赖的子crate:
- 在
gen目录下创建Cargo.toml,配置为lib crate:
[package] name = "my-model-v1" version = "0.1.0" edition = "2021" [dependencies] prost = "0.12" prost-types = "0.12" serde = { version = "1.0", features = ["derive"] } # 添加其他需要的依赖
- 主项目的
Cargo.toml中添加这个本地依赖:
[dependencies] my-model-v1 = { path = "./gen" }
- 在主库的
lib.rs中直接引入并导出:
pub use my_model_v1::*;
这种方式完全不需要#[path],引用逻辑和普通第三方依赖一致,更符合Rust模块系统的惯例。
3. 是否需要工作区?
如果你的项目规模不大,目前完全不需要工作区。工作区主要用于拆分多个关联crate的大型项目,当前仅需处理生成代码的场景,用本地依赖子crate的方式就足够简洁。如果后续项目拆分出多个独立模块,再考虑引入工作区统一管理即可。
内容的提问来源于stack exchange,提问作者Goldie

