如何让Cargo复用已编译本地Rust库并避免依赖全量重建?
问题描述
我在同一个单体仓库(monorepo)中维护一个Rust主项目和一个Rust库项目,主项目的Cargo.toml通过本地路径引用该库:
aws_tools = { path = "../../shared/rust/my_tools/" }
编译库项目会生成libmy_tools.rlib文件,但主项目编译时并不会复用该文件,而是重新编译库的所有源码,导致无法利用已编译库加速Docker容器构建。
此外,每当更新aws_tools的任意源码文件时,pw_uploader的所有依赖都会重新构建,而非仅aws_tools本身。请问如何解决这两个问题?
我的Dockerfile
FROM --platform=linux/arm64 rust:slim as build # Install required dependencies RUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential \ pkg-config \ libssl-dev # Copy files for the library projects WORKDIR /usr/src/my_application/shared/rust/aws_tools COPY ./shared/rust/aws_tools/Cargo.toml ./shared/rust/aws_tools/Cargo.lock ./ COPY ./shared/rust/aws_tools/src/ ./src/ # Create a new empty shell project WORKDIR /usr/src/my_application/docker RUN cargo init --bin pw-uploader WORKDIR /usr/src/my_application/docker/pw-uploader # Copy the Cargo.toml files for the main project COPY ./docker/pw-uploader/Cargo.toml ./docker/pw-uploader/Cargo.lock ./ # Build the dependencies for the main project RUN cargo build --release # Build the main project COPY ./docker/pw-uploader/src/ ./src/ RUN touch ./src/main.rs && cargo build --release FROM --platform=linux/arm64 debian:bullseye RUN apt-get update RUN apt-get upgrade RUN apt-get install -y --no-install-recommends libc6-dev RUN apt-get install -y --no-install-recommends libssl-dev RUN apt-get install -y --no-install-recommends ca-certificates RUN apt-get clean RUN update-ca-certificates WORKDIR /usr/src/app # Copy the built project and its dependencies from the main project build image COPY --from=build /usr/src/my_application/docker/pw-uploader/target/release/pw_uploader . # Start the application CMD ["./pw_uploader"]
解决方案
一、解决主项目复用已编译库的问题
核心是让Cargo共享编译产物目录,自动识别并复用已编译的库文件。
1. 设置共享编译目录
在Docker的build阶段,通过CARGO_TARGET_DIR环境变量指定统一的编译产物目录,让库和主项目的编译结果都存放在这里,Cargo会自动复用已有产物:
ENV CARGO_TARGET_DIR=/usr/src/target
2. 提前编译库项目
在构建主项目之前完成库的编译,产物存入共享目录,主项目构建时直接取用:
# 构建库项目 WORKDIR /usr/src/my_application/shared/rust/aws_tools COPY ./shared/rust/aws_tools/Cargo.toml ./shared/rust/aws_tools/Cargo.lock ./ COPY ./shared/rust/aws_tools/src/ ./src/ RUN cargo build --release
二、解决更新库时全量重建依赖的问题
问题根源是Docker构建缓存失效,通过拆分构建步骤精准控制缓存触发条件。
1. 拆分库的构建步骤
先复制库的Cargo.toml和Cargo.lock缓存依赖下载,再复制真实源码编译,确保只有源码变更时才重建库:
WORKDIR /usr/src/my_application/shared/rust/aws_tools # 先缓存依赖 COPY ./shared/rust/aws_tools/Cargo.toml ./shared/rust/aws_tools/Cargo.lock ./ RUN mkdir src && echo "fn main() {}" > src/lib.rs && cargo build --release # 再复制真实源码并重新构建 COPY ./shared/rust/aws_tools/src/ ./src/ RUN cargo build --release
2. 拆分主项目的构建步骤
同样先缓存主项目依赖,再复制源码构建,使用--only-deps参数只构建依赖(包括已编译的库):
WORKDIR /usr/src/my_application/docker/pw-uploader # 缓存主项目依赖 COPY ./docker/pw-uploader/Cargo.toml ./docker/pw-uploader/Cargo.lock ./ RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release --only-deps # 复制真实源码构建主项目 COPY ./docker/pw-uploader/src/ ./src/ RUN touch ./src/main.rs && cargo build --release
完整优化后的Dockerfile
FROM --platform=linux/arm64 rust:slim as build # 设置共享编译目录 ENV CARGO_TARGET_DIR=/usr/src/target # 安装系统依赖并清理缓存 RUN apt-get update && \ apt-get install -y --no-install-recommends build-essential pkg-config libssl-dev && \ rm -rf /var/lib/apt/lists/* # 构建库项目:先缓存依赖,再编译真实源码 WORKDIR /usr/src/my_application/shared/rust/aws_tools COPY ./shared/rust/aws_tools/Cargo.toml ./shared/rust/aws_tools/Cargo.lock ./ RUN mkdir src && echo "fn main() {}" > src/lib.rs && cargo build --release COPY ./shared/rust/aws_tools/src/ ./src/ RUN cargo build --release # 构建主项目:先缓存依赖,再编译真实源码 WORKDIR /usr/src/my_application/docker/pw-uploader COPY ./docker/pw-uploader/Cargo.toml ./docker/pw-uploader/Cargo.lock ./ RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release --only-deps COPY ./docker/pw-uploader/src/ ./src/ RUN touch ./src/main.rs && cargo build --release # 生成最终镜像 FROM --platform=linux/arm64 debian:bullseye RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -y --no-install-recommends libc6-dev libssl-dev ca-certificates && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ update-ca-certificates WORKDIR /usr/src/app COPY --from=build /usr/src/target/release/pw_uploader . CMD ["./pw_uploader"]
优化效果
- 主项目构建时直接复用已编译的库文件,无需重新编译库源码
- 更新库源码时,仅重新构建库本身,主项目的其他依赖不会触发重建
- 充分利用Docker缓存,大幅缩短构建时间
内容的提问来源于stack exchange,提问作者Oleksii
相关产品推荐
相关产品推荐

