rust Cargo是否可以下载并构建依赖项,而无需构建应用程序?

au9on6nz  于 2023-01-05  发布在  Go
关注(0)|答案(6)|浏览(336)

有没有一种方法可以告诉Cargo安装并构建我的所有依赖项,但不尝试构建我的应用程序?
我原以为cargo install会做到这一点,但实际上它也一直在构建我的应用程序。我希望达到这样一种状态,即cargo build会发现所有依赖项都已准备好使用,但不涉及/src目录。

我真正想要实现的

我正在尝试为Rust应用程序构建Docker映像,我想在其中执行以下步骤:
构建时间(docker build .):
1.导入安装了Ruster工具Docker映像
1.添加我的Cargo.toml和Cargo.lock文件
1.下载并生成所有依赖项
1.添加我的源目录到这图象
1.生成我的源代码
运行时间(docker run ...):
1.运行应用程序
我已经尝试了下面的Dockerfile,但是所指示的步骤也构建了我的应用程序(当然失败了,因为源目录还不存在):

FROM jimmycuadra/rust

ADD Cargo.toml /source
ADD Cargo.lock /source

RUN cargo install # <-- failure here

ADD src /source/src
RUN cargo build

ENTRYPOINT cargo run

我之所以想把依赖项的安装步骤和实际构建应用程序分开,是因为如果我不修改依赖项,我希望Docker能够使用一个缓存映像,并且所有依赖项都已经安装和构建好了。因此,我不能ADD /src /source/src,直到安装依赖项 * 之后 *,因为这会在我修改自己的代码时使缓存映像无效。

wwtsj6pe

wwtsj6pe1#

据我所知,Cargo中没有对构建依赖项的本地支持。有an open issue for it。如果您可以向Cargo提交一些东西来完成它,或者创建一个第三方Cargo插件,我不会感到惊讶。我也希望cargo doc具有此功能,因为我自己的代码太过破碎而无法编译; -)
但是,我维护的Rust playground确实实现了您的最终目标。有一个base Docker container,它安装了Rustup,并在一个Cargo.toml中复制了所有可用于Playground的板条箱。构建步骤创建一个空白项目(使用一个虚拟的src/lib.rs),然后调用cargo buildcargo build --release来编译板条箱:

RUN cd / && \
    cargo new playground
WORKDIR /playground

ADD Cargo.toml /playground/Cargo.toml
RUN cargo build
RUN cargo build --release
RUN rm src/*.rs

所有下载的板条箱存储在Docker映像的$HOME/.cargo目录中,所有构建的板条箱存储在应用程序的target/{debug,release}目录中。
稍后,真正的源文件被复制到容器中,并且可以使用现在编译好的crates再次执行cargo build/cargo run
如果您正在构建一个可执行项目,那么您还需要在Cargo. lock中进行复制。

busg9geu

busg9geu2#

如果你添加一个虚拟的main或lib文件,你可以使用cargo build来下拉依赖项。我目前正在使用这个解决方案来处理我的基于Docker的项目:

COPY Cargo.toml .
RUN mkdir src \
    && echo "// dummy file" > src/lib.rs \
    && cargo build

我使用的是--volumes,所以我已经完成了这一步。主机卷进入并删除了虚拟文件,当我稍后构建源代码时,cargo使用缓存的依赖项。如果您稍后想添加COPY(或ADD)并使用缓存的依赖项,这个解决方案也同样有效。

pepwfjgg

pepwfjgg3#

基于GitHub评论

FROM rust:1.37

WORKDIR /usr/src

# Create blank project
RUN USER=root cargo new PROJ

# We want dependencies cached, so copy those first.
COPY Cargo.toml /usr/src/PROJ/
COPY Cargo.lock /usr/src/PROJ/

WORKDIR /usr/src/PROJ

# This is a dummy build to get the dependencies cached.
RUN cargo build --release

# Now copy in the rest of the sources
COPY MyPROJECT/src /usr/src/PROJ/src/

# This is the actual build.
RUN cargo build --release \
    && mv target/release/appname /bin \
    && rm -rf /usr/src/PROJ

WORKDIR /

EXPOSE 8888

CMD ["/bin/appname"]
nhhxz33t

nhhxz33t4#

cargo-chef工具就是为了解决这个问题而设计的。下面是README中的一个例子,告诉你如何在Dockerfile中使用它:

FROM lukemathwalker/cargo-chef as planner
WORKDIR app
COPY . .
RUN cargo chef prepare  --recipe-path recipe.json

FROM lukemathwalker/cargo-chef as cacher
WORKDIR app
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json

FROM rust as builder
WORKDIR app
COPY . .
# Copy over the cached dependencies
COPY --from=cacher /app/target target
COPY --from=cacher $CARGO_HOME $CARGO_HOME
RUN cargo build --release --bin app

FROM rust as runtime
WORKDIR app
COPY --from=builder /app/target/release/app /usr/local/bin
ENTRYPOINT ["/usr/local/bin/app"]
mpbci0fu

mpbci0fu5#

我只是想把这个贴在这里,这样其他人就可以看到它的发展。我刚刚开始使用Docker的一个实验工具,叫做Cargo-Wharf(https://github.com/denzp/cargo-wharf/tree/master/cargo-wharf-frontend)。它是一个Docker BuildKit前端,为您缓存构建的货物依赖项。如果您只更改了一个源文件,这是当你调用docker build时唯一被重建的东西。你可以通过注解你的Cargo.toml文件来使用它,然后将Docker指向你的Cargo.toml而不是Docker文件。去看看吧,这正是我想要的。(我与这个项目毫无关系。)

5lhxktic

5lhxktic6#

可以通过cargo initcargo buildcargo install来完成。例如,对于名为foo的项目,定义以下Dockerfile

FROM rust:slim-bullseye

# Build dependencies only.
RUN cargo init foo
COPY Cargo.toml foo/
RUN cargo build --release; \
    rm -rf foo

# Install `foo`.
COPY . .
RUN echo "// force Cargo cache invalidation" >> foo/src/main.rs; \
    cargo install --path foo

CMD ["foo"]

在这里,cargo init创建Cargo所需的占位符文件,cargo build构建在Cargo.toml中指定的依赖项,cargo install创建foo二进制文件。Docker继续构建由cargo init foo创建的默认项目。以上通过追加// force Cargo cache invalidation强制更新main.rs解决了此问题。
若要避免由于生成上下文和层较大而导致生成速度较慢,请确保通过.dockerignore忽略不重要的文件夹(如target)。例如,定义以下.dockerignore

**/*.lock
LICENSE
README.md
target

相关问题