如何发布子 crate?
解读
在 Rust 生态里,“子 crate”通常指**工作区(workspace)**里的成员 crate,而不是 git submodule 或 path 依赖。面试官问“如何发布”,核心想确认两点:
- 你是否理解 Cargo 工作区 的发布边界——workspace 本身不可发布,只有单个 crate 可发布;
- 你是否掌握国内网络环境下( crates.io 访问受限)的完整发布流程,包括本地验证、版本同步、依赖源切换、CI 集成等细节。
回答时若只说一句cargo publish会被视为“学生级答案”;必须体现出工程化落地经验。
知识点
- 工作区与 package 边界:workspace 根目录下
Cargo.toml的[workspace]仅做聚合,不含[package]字段,因此无法publish;只有成员目录下包含[package]的 crate 才能发布。 - 版本号一致性:workspace 成员之间若用
path = "../xxx"依赖,发布前需把版本号改成已发布版本或同次发布版本,否则 crates.io 拒绝上传。 - 国内网络:crates.io 索引走 git 协议,443 端口常被限速;需配置 国内镜像源(如 tuna、ustc)或代理;发布阶段仍需走 https 直链,需确保 443 端口畅通。
- --dry-run 与本地验证:
cargo publish --dry-run会在本地完整走一遍打包、校验、编译流程,提前暴露 include/exclude 字段拼写错误、README 缺失、license 文件未跟踪等问题。 - token 管理:
cargo login生成的 API Token 默认保存在~/.cargo/credentials,CI 场景需通过环境变量CARGO_REGISTRY_TOKEN注入,避免明文落盘。 - 子 crate 发布顺序:若 A 依赖 B,必须先
cargo publishB,再把 A 的Cargo.toml里 B 的依赖版本指向刚发布的版本号,然后发布 A;workspace 里可用 cargo-release 工具一键完成“自底向上”顺序发布并自动打 git tag。 - yank 与撤销:发布后 72 小时内可
cargo yank --vers x.y.z下架,但文件不可删除,国内大厂审计要求“禁止 yank”时,需在 CI 加脚本检查版本号是否已存在。 - 私有 registry:企业内网场景用 cargo-zng-registry 或 kellnr 搭建私有源,发布命令换成
cargo publish --registry mycorp,需在~/.cargo/config.toml里配置[registries.mycorp]索引地址与 token。
答案
-
确认目录结构
workspace 根Cargo.toml仅含[workspace] members = ["crates/foo", "crates/bar"]子 crate
crates/foo/Cargo.toml必须含[package] name = "foo" version = "0.1.0" license = "MIT OR Apache-2.0" description = "xxx" repository = "https://github.com/yourname/repo"缺少任何必填字段都会导致
cargo publish直接失败。 -
国内网络前置配置
在~/.cargo/config.toml加入[source.crates-io] replace-with = 'ustc' [source.ustc] registry = "https://mirrors.ustc.edu.cn/crates.io-index"发布阶段镜像源不影响上传,但可显著加快依赖校验速度;若公司出口封 443,需临时走
export https_proxy=http://proxy.xxx:端口。 -
本地一次性验证
cd crates/foo cargo publish --dry-run观察输出是否包含
Packaged 12 files, 46.3KiB若出现
warning: fileREADME.mdis not included,检查include = ["src/", "README.md", "LICENSE-*"]是否拼错。 -
登录与发布
cargo login # 粘贴 crates.io 个人中心生成的 API Token cargo publish --no-verify--no-verify可跳过再次编译,节省 30~60 秒;首次发布无需加--no-verify,因为 crates.io 会强制做全量编译校验。 -
顺序发布兄弟 crate
若bar依赖foo = { version = "0.1", path = "../foo" },先发布foo,再把bar的依赖改为foo = "0.1.0",再发布bar;可用工具链cargo install cargo-release cargo release patch --execute它会自动按拓扑序发布并打 tag。
-
验证已发布
新建空白目录执行cargo new test-use cd test-use cargo add foo@0.1 cargo check确保拉取的是 crates.io 版本而非本地 path,防止“本地能编、线上失败”。
拓展思考
-
CI 全自动发布:在 GitHub Actions 里用
on: push: tags: - '*'触发,步骤:- 设置
CARGO_REGISTRY_TOKEN为 GitHub secret; cargo install cargo-release;cargo release ${{ github.ref_name }} --execute --no-confirm;- 发布完成后通过企业微信/飞书机器人通知版本号。
注意:国内 GitHub Runner 需选香港节点,否则cargo publish上传阶段超时。
- 设置
-
语义化版本与破坏性变更:workspace 多 crate 共用一张变更日志,需在根目录维护
CHANGELOG.md,用 cargo-smart-release 自动解析 PR label 生成日志,避免人工漏写导致用户升级失败。 -
私有 crate 混用:若部分子 crate 含源码专利不便公开,可配置
[package] publish = ["mycorp"]阻止误发到 crates.io;CI 里用
cargo publish --registry mycorp统一收口,实现“公开 crate 走 crates.io,内部 crate 走私有源” 的混合策略。 -
回滚方案:一旦
cargo yank被审计禁止,可在下一个 patch 版本里revert 问题代码并立即发布,再通过内部文档通知业务方升级;同时把出问题的版本号写入deny.toml黑名单,用 cargo-deny 在 CI 阶段强制拦截引用,实现“物理隔离”而非物理删除。