Может ли Cargo загружать и строить зависимости без создания приложения?

Есть ли способ сказать Cargo для установки и сборки всех моих зависимостей, но не попытки создать мое приложение?

Я думал, что cargo install будет делать это, но на самом деле все идет так же, как и при создании моего приложения. Я хочу добраться до состояния, в котором cargo build найдет все зависимости, готовые к использованию, но не касаясь каталога /src.


То, что я действительно пытаюсь сделать:

Я пытаюсь создать образ Docker для приложения Rust, где я бы хотел сделать следующие шаги:

Время сборки (docker build.):

  1. импортировать изображение докера с установленным ржавчиной
  2. добавьте мои файлы Cargo.toml и Cargo.lock
  3. загружать и строить все зависимости
  4. добавить исходный каталог к изображению
  5. создать исходный код

Время выполнения (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 до тех пор, пока не установит зависимости, поскольку это приведет к аннулированию кэшированного изображения при изменении моего собственного кода.

Ответ 1

Насколько мне известно, нет никакой поддержки для создания только зависимостей в Cargo. Для него есть открытый вопрос. Я бы не удивился, если бы вы могли что-то передать Каргу, чтобы выполнить его, или, возможно, создать сторонний грузовой аддон. Я хотел эту функциональность для cargo doc, когда мой собственный код слишком сломан, чтобы компилировать ;-)

Тем не менее, площадка Rust, которую я поддерживаю, достигает конечной цели. Там есть базовый контейнер Docker, который устанавливает Rustup и копирует в Cargo.toml со всеми ящиками, доступными для игровой площадки. На этапах сборки создается пустой проект (с манекеном src/lib.rs), затем вызывается cargo build и cargo 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 image $HOME/.cargo и все встроенные ящики хранятся в каталогах target/{debug,release}.

Позже, реальные исходные файлы копируются в контейнер, а cargo build cargo run/cargo run может быть выполнена снова, используя теперь скомпилированные ящики.

Если вы строите исполняемый проект, вы также хотите скопировать в Cargo.lock.

Ответ 2

Если вы добавите фиктивный основной файл или файл lib, вы можете использовать cargo build чтобы просто сбрасывать зависимости. В настоящее время я использую это решение для моего проекта на базе Docker:

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

Я использую --volumes, поэтому я закончил на этом этапе. Хост-хосты входят и сбрасывают фиктивный файл, а груз использует кэшированные зависимости, когда я иду для создания источника позже. Это решение будет работать так же хорошо, если вы хотите позже добавить COPY (или ADD) и использовать кэшированные зависимости.

Ответ 3

Основано на комментарии 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"]