Cargo Package
离线编译策略
简单地讲,cargo
为Package
提供了两套【离线编译】解决方案:
- 方案一:
cargo fetch
cargo build --offline
- 方案二:
cargo vendor
修改.cargo/config.toml
文件cargo build
两套方案的共同点
cargo fetch
与cargo vendor
命令- 【执行-位置】都需要在
Cargo Package
工程根目录被执行。 - 【执行-时间】都需要在工程构建程序(无论是
build.rs
还是shell
脚本)被启动前,被预先执行。
- 【执行-位置】都需要在
- 无论依赖项的来源是
crates.io
还是github
,它们都可被预拉取和缓存至本地。
两套方案的差别
- 依赖项
crate
源码的储存位置crate.io
依赖项 ->$CARGO_HOME/registry/src
github
依赖项 ->$CARGO_HOME/git/checkouts
cargo fetch
缓存依赖项源码于$CARGO_HOME
目录下。更具体地进,cargo vendor
缓存依赖项源码于Cargo Package
工程根目录下的vendor
子文件夹里。
- 依赖项
crate
的共享范围vendor
文件夹馁馁地就是rust
版的node_modules
。- 若将
vendor
依赖目录在多个Cargo Package
工程之间共享,需要额外地配置.cargo/config.toml
文件和对多个工程的文件系统位置做一些约定。这要比npm - node_modules
麻烦不少 — 回头单独写篇文章分享之。 - 由
cargo fetch
缓存的依赖项源码可被同一台机器上的所有Cargo Package
工程所共享。 - 由
cargo vendor
缓存的依赖项源码仅服务于当前Cargo Package
工程。
- 与
CI
系统集成方式(比如,Jenkins
)- 首先,
cargo vendor
命令需要由 @程序员,在个人电脑上,在代码提交前,执行一次。于是,vendor
文件夹出现。 - 然后,将·
cargo vendor
命令打印至【标准输出】的配置代码(如下)·复制到.cargo/config.toml
配置文件内。 [source.crates-io]replace-with = "vendored-sources"[source."https://github.com/shadowsocks/crypto"]git = "https://github.com/shadowsocks/crypto"branch = "master"replace-with = "vendored-sources"[source.vendored-sources]directory = "vendor" 若你的Cargo Package
工程曾经配置过【源码替换】规则(真高级),那么请合并(而不仅是追加)[source.***]
配置代码。 - 接着,将工程根目录下的
vendor
文件夹和.cargo/config.toml
配置文件,随业务程序,一起提交至git
仓库。 - 在打包编译过程中,
- 业务代码
- 依赖源码
Cargo.toml
.cargo/config.toml
Jenkins
会git clone
到上述所有文件,包括:cargo build
命令也不需要--offline
命令行参数了,因为【目录·源码替换】配置规则会生效和告诉cargo
从本地硬盘的何处寻找依赖项crate
源码。 题外话,没有想到吧!在这影响依赖项“寻址”指向的机制不是【依赖重载[patch.***]
】,而是【源码替换[source.***]
】。我也挺意外的。- 首先,
cargo fetch
命令需要由 @CI
管理员,在Jenkins
机器上,在启动打包jobs
以前,连网执行一次。 - 然后,在打包过程中,
cargo build --offline
命令才能在$CARGO_HOME
目录下找到预缓存的依赖项源码。其中,命令行参数--offline
会“短路”一切网络请求,包括: - 确认
Cargo.lock
是否已经反映了每个依赖项的最新语义兼容版本。 - 下载依赖项
crate
源码 cargo fetch
方案·集成步骤: 对程序员来说,这可能不那么爽。毕竟,每次依赖升级,咱们都不得不走流程,编故事,写报告,请 @CI
管理员 给执行一下cargo fetch
命令。cargo vendor
方案·集成步骤:
- 首先,
cargo vendor
性能最佳·参数组合
cargo vendor --no-delete --versioned-dirs --respect-source-config
--no-delete
不删除上一次执行cargo vendor
时留下的vendor
文件夹。这样下载过的crate
源码就不会再重新下载了。--versioned-dirs
给每个依赖项目录名追加以-
开头的版本号后缀(例如,base64-0.5.2
)。这样,不用刻意地浏览每个依赖项的Cargo.toml
文件,便可知晓它们的版本信息。--respect-source-config
若你的工程早先就已经配置过【源码替换】[source.***]
配置块,cargo
将对旧配置做兼容处理。否则,旧配置就会被无视了。
番外篇
虽然上面讲了那么多,但其实仅只绕过了【依赖项源码下载】的耗时环节。但是,cargo
打包编译慢,又何止于网络慢,编译本身也是“重灾区”。所以,若你的CI
打包策略是:
- 抹除整个工程目录 — 毛都不剩
git
捡出业务代码 — 内网应该很快- 下载依赖项 — 走
cargo fetch / vendor
的缓存,应该也很快 - 编译依赖项 — 我若说“不慢”,你敢信?
的话,那么上述的长篇大论仅只节省了#3
的延时。而我要在此推荐的【究级】“补刀”配置却能够缩短#4
的耽搁。即,给.cargo/config.toml
文件添加(或合并)一段配置(如下)
[build]target-dir = "../<工程名>-target"
将整个编译输出目录“请”出工程文件夹。于是,
- 【编译输出文件夹】将和【
Cargo Package
工程】处于平级目录且名曰“<工程名>-target” Jenkins
不会再删除【编译输出目录】及其缓存的编译中间文件,因为它们都不在【工程目录】中。- 下次再对该
Cargo Package
工程编译,将启用【增量编译】处理流程。这馁馁地要比【全量编译】快速得多!
最后,cargo
打包编译的最后两步都有了缓存做支撑,工程的编译速度进一步被提高。完美!!!
结束语
这次就分享这些。总的来说,我对rust
编程的实践机会还是非常有限的。所以,文章中总结的内容有疏漏之处,还请路过的神仙哥哥与神仙妹妹指正,和多发评论呀!