cargo icon indicating copy to clipboard operation
cargo copied to clipboard

cargo build --dependencies-only

Open nagisa opened this issue 8 years ago • 329 comments

cargo team notes:


There should be an option to only build dependencies.

nagisa avatar May 04 '16 15:05 nagisa

@nagisa, Why do you want it?

KalitaAlexey avatar Jan 17 '17 20:01 KalitaAlexey

I do not remember exactly why, but I do remember that I ended just running rustc manually.

nagisa avatar Jan 17 '17 20:01 nagisa

@posborne, @mcarton, @Devyn, You reacted with thumbs up. Why do you want it?

KalitaAlexey avatar Jan 17 '17 20:01 KalitaAlexey

Sometimes you add a bunch of dependencies to your project, know it will take a while to compile next time you cargo build, but want your computer to do that as you start coding so the next cargo build is actually fast. But I guess I got here searching for a cargo doc --dependencies-only, which allows you to get the doc of your dependencies while your project does not compile because you'd need the doc to know how exactly to fix that compilation error you've had for a half hour :smile:

mcarton avatar Jan 17 '17 20:01 mcarton

As described in #3615 this is useful with build to setup a cache of all dependencies.

gregwebs avatar Jan 30 '17 22:01 gregwebs

@gregwebs out of curiosity do you want to cache compiled dependencies or just downloaded dependencies? Caching compiled dependencies isn't implemented today (but would be with a command such as this) but downloading dependencies is available via cargo fetch.

alexcrichton avatar Jan 31 '17 04:01 alexcrichton

Generally, as with my caching use case, the dependencies change infrequently and it makes sense to cache the compilation of them.

The Haskell tool stack went through all this and they seemed to generally decided to merge things into a single command where possible. For fetch they did end up with something kinda confusing though: build --dry-run --prefetch. For build --dependencies-only mentioned here they do have the same: build --only-dependencies

gregwebs avatar Jan 31 '17 04:01 gregwebs

@gregwebs ok thanks for the info!

alexcrichton avatar Jan 31 '17 17:01 alexcrichton

@alexcrichton, It looks like I should continue my work on the PR. Will Cargo's team accept it?

KalitaAlexey avatar Jan 31 '17 17:01 KalitaAlexey

@KalitaAlexey I personally wouldn't be convinced just yet, but it'd be good to canvas opinions from others on @rust-lang/tools as well

alexcrichton avatar Feb 02 '17 18:02 alexcrichton

@alexcrichton, Anyway I have no time right now)

KalitaAlexey avatar Feb 02 '17 18:02 KalitaAlexey

I don't see much of a use case - you can just do cargo build and ignore the output for the last crate. If you really need to do this (for efficiency) then there is API you can use.

nrc avatar Feb 02 '17 18:02 nrc

What's the API?

gregwebs avatar Feb 04 '17 19:02 gregwebs

Implement an Executor. That lets you intercept every call to rustc and you can do nothing if it is the last crate.

nrc avatar Feb 06 '17 20:02 nrc

I wasn't able to find any information about an Executor for cargo. Do you have any links to documentation?

gregwebs avatar Feb 06 '17 20:02 gregwebs

Docs are a little thin, but start here: https://github.com/rust-lang/cargo/blob/609371f0b4d862a94e2e3b8e4e8c2a4a2fc7e2e7/src/cargo/ops/cargo_rustc/mod.rs#L62-L64

You can look at the RLS for an example of how to use them: https://github.com/rust-lang-nursery/rls/blob/master/src/build.rs#L288

nrc avatar Feb 06 '17 20:02 nrc

A question of Stack Overflow wanted this feature. In that case, the OP wanted to build the dependencies for a Docker layer.

A similar situation exists for the playground, where I compile all the crates once. In my case, I just put in a dummy lib.rs / main.rs. All the dependencies are built, and the real code is added in the future.

shepmaster avatar Feb 10 '17 03:02 shepmaster

@shepmaster unfortunately the proposed solution wouldn't satisfy that question because a Cargo.toml won't parse without associated files in src (e.g. src/lib.rs, etc). So that question would still require "dummy files", in which case it wouldn't specifically be serviced by this change.

alexcrichton avatar Feb 10 '17 15:02 alexcrichton

I ended up here because I also am thinking about the Docker case. To do a good docker build I want to:

COPY Cargo.toml Cargo.lock /mything

RUN cargo build-deps --release  # creates a layer that is cached

COPY src /mything/src

RUN cargo build --release       # only rebuild this when src files changes

This means the dependencies would be cached between docker builds as long as Cargo.toml and Cargo.lock doesn't change.

I understand src/lib.rs src/main.rs are needed to do a good build, but maybe build-deps simply builds all the deps.

lolgesten avatar Oct 09 '17 19:10 lolgesten

The dockerfile template in shepmaster's linked stackoverflow post above SOLVES this problem

I came to this thread because I also wanted the docker image to be cached after building the dependencies. After later resolving this issue, I posted something explaining docker caching, and was informed that the answer was already linked in the stackoverflow post. I made this mistake, someone else made this mistake, it's time to clarify.

RUN cd / && \
    cargo new playground
WORKDIR /playground                      # a new project has a src/main.rs file

ADD Cargo.toml /playground/Cargo.toml 
RUN cargo build                          # DEPENDENCIES ARE BUILD and CACHED
RUN cargo build --release
RUN rm src/*.rs                          # delete dummy src files

# here you add your project src to the docker image

After building, changing only the source and rebuilding starts from the cached image with dependencies already built.

ghost avatar Oct 09 '17 19:10 ghost

someone needs to relax...

lolgesten avatar Oct 09 '17 20:10 lolgesten

Also @KarlFish what you're proposing is not actually working. If using FROM rust:1.20.0.

  1. cargo new playground fails because it wants USER env variable to be set.
  2. RUN cargo build does not build dependencies for release, but for debug. why do you need that?

lolgesten avatar Oct 09 '17 20:10 lolgesten

Here's a better version.

FROM rust:1.20.0

WORKDIR /usr/src

# Create blank project
RUN USER=root cargo new umar

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

WORKDIR /usr/src/umar

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

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

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

WORKDIR /

EXPOSE 3000

CMD ["/bin/umar"]

lolgesten avatar Oct 09 '17 20:10 lolgesten

You can always review the complete Dockerfile for the playground.

shepmaster avatar Oct 09 '17 20:10 shepmaster

Hi! What is the current state of the --deps-only idea? (mainly for dockerization)

maelvls avatar Nov 10 '17 16:11 maelvls

I agree that it would be really cool to have a --deps-only option so that we could cache our filesystem layers better in Docker.

I haven't tried replicating this yet, but it looks very promising. This is in glibc and not musl, by the way. My main priority is to get to a build that doesn't take 3-5 minutes ever time, not a 5 MB alpine-based image.

AdrienneCohea avatar Feb 03 '18 21:02 AdrienneCohea

I ran into wanting this today.

steveklabnik avatar Feb 16 '18 14:02 steveklabnik

@steveklabnik can you share more details about your case? Why would building only the dependencies be useful? Is starting with an empty lib.rs/main.rs not applicable to your situation?

shepmaster avatar Feb 16 '18 15:02 shepmaster

As an aside, a cargo extension (cargo-prebuild?) could probably move aside the main.rs / lib.rs, replace it with an empty version, call cargo build, then move it back. That would "solve" the problem.

shepmaster avatar Feb 16 '18 15:02 shepmaster

I wanted to time a clean build, but of my crate only, and not its dependencies. The easiest way to do that is to cargo clean followed by a hypothetical cargo build --deps-only, then time a cargo build.

Yeah, I mean, I could replace everything, and then pull it back, but that feels like working around things rather than doing what I actually want to do.

steveklabnik avatar Feb 16 '18 15:02 steveklabnik