用 cargo 的 target-dir 分摊编译盘占用的一次记录
项目是 windows 上跑的,rustc 1.78,workspace 一共 11 个 crate,debug 编译完之后 target 目录 18G 左右。机器是一块 512G 的固态,系统盘只剩 30G 出头,每次 cargo build 的时候磁盘写满,链接器报错,报错信息还停在 link.exe 那一层,看不出是盘的问题。
先量了一下体积,确认大头在哪:
du -sh target/debug/* 2>/dev/null | sort -h | tail -20
incremental、deps、build 三个目录加起来占了一半以上,其中 deps 里堆了多个版本的同一个依赖。真正的问题是 workspace 里几个成员分别 feature 组合不同,cargo 会为不同 feature 组合各存一份编译产物。
我的做法是把 target-dir 挪到第二块盘,并且按 workspace 分开:
# .cargo/config.toml
[build]
target-dir = "D:/cargo-targets/my-ws"
注意这个配置放在仓库根目录的 .cargo/config.toml 里,只对本仓库生效,不会污染全局。如果不想改文件,用环境变量也行:
CARGO_TARGET_DIR=D:/cargo-targets/my-ws cargo build
另外把 incremental 关掉做一次完整验证,能省下不少空间,代价是后续增量编译变慢:
[profile.dev]
incremental = false
为什么这样能降下来:target-dir 只是换位置,不减少体积;真正的收益在于把大文件写操作从系统盘分出去,避免系统盘被写满导致的链接失败。而按 workspace 独立目录,是为了避免多个项目共用一个 target 时,cargo 反复判定指纹失效、来回重编。我试过所有项目共用一个目录,切换项目时几乎每次都触发全量重编,时间成本比省下的盘还贵。
会失效的地方有几个。第一,绝对路径写进 config.toml 之后,团队里其他人机器上没有 D 盘,仓库直接编不了,稳妥的是用环境变量,或者只在自己机器上放全局配置。第二,挪到机械盘或网络盘之后,链接阶段的小文件随机读写会明显变慢,我这边机械盘上全量编译从 4 分钟涨到 11 分钟。第三,cargo clean 只清当前 target-dir,换过目录之后旧目录会变成残留,需要手动删。第四,rust-analyzer 读的是同一份配置,挪完要重启一下,否则 proc-macro 会报找不到产物。
我现在的做法是:全局 config 里不设 target-dir,每个大 workspace 自己在根目录放一份,路径用相对仓库的位置或者干脆靠环境变量注入。
想问一下,你们 workspace 里多个成员 feature 组合差异大的时候,是拆成独立 workspace 分别编译,还是硬扛重复产物?
0 条评论
还没有评论,写下第一条。