Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upGitHub is where the world builds software
Millions of developers and companies build, ship, and maintain their software on GitHub — the largest and most advanced development platform in the world.
cargo build --dependencies-only #2644
Comments
|
@nagisa, |
|
I do not remember exactly why, but I do remember that I ended just running rustc manually. |
|
Sometimes you add a bunch of dependencies to your project, know it will take a while to compile next time you |
|
As described in #3615 this is useful with |
|
@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 |
|
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 |
|
@gregwebs ok thanks for the info! |
|
@alexcrichton, |
|
@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, |
|
I don't see much of a use case - you can just do |
|
What's the API? |
|
Implement an |
|
I wasn't able to find any information about an |
|
Docs are a little thin, but start here: cargo/src/cargo/ops/cargo_rustc/mod.rs Lines 62 to 64 in 609371f 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 |
|
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 |
|
@shepmaster unfortunately the proposed solution wouldn't satisfy that question because a |
|
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 changesThis means the dependencies would be cached between docker builds as long as I understand |
The dockerfile template in shepmaster's linked stackoverflow post above SOLVES this problemI 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.
After building, changing only the source and rebuilding starts from the cached image with dependencies already built. |
|
someone needs to relax... |
|
Also @karlfish what you're proposing is not actually working. If using
|
|
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"] |
|
You can always review the complete Dockerfile for the playground. |
|
Hi! |
|
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. |
|
I've been lurking on this thread for quite a while, and might have a helpful tidbit for those looking for a docker workaround. I did a scan and couldn't see anywhere this has been suggested, but the following seems to work for caching deps for me in a docker build:
Pepsi is just the codename for a project of mine, and Anyway, not looking to comment either way, just thought I'd leave this here for docker folks looking for a quick workaround! |
|
@trezm I have been playing with the same docker commands but ran into some strange thing where it is not rebuilding the binary. Does it have to do with timestamps of the main.rs file? Why did the build rs fix the problem? |
|
@camerondavison do be 100% honest, I'm really not sure why the build.rs affects the result! I came across it as a solution by accident. I had a project that I have a dockerfile for that uses tonic, so I needed a build.rs to build proto files. I noticed that I could super simplify the Dockerfile for that project, but when I copied the same Dockerfile to a new project (sans build.rs) it no longer worked because of what you mentioned. I added the build.rs file back with a single dummy println and it seemed to work again! Really not sure why this would change anything, maybe something to do with the presence of a build.rs file forcing cargo to look at the actual timestamp on all the files? This is me wildly speculating, but I encourage you to try adding a dummy build.rs and see if you get the same results! |
|
@trezm adding a build.rs file with fn main() {}does fix the problem. so crazy. I am going to keep trying to figure out why. EDIT: found a solution FROM rust:1.44 as build
# app
ENV app=my-app
# dependencies
WORKDIR /tmp/${app}
COPY Cargo.toml Cargo.lock ./
# compile dependencies
RUN set -x\
&& mkdir -p src\
&& echo "fn main() {println!(\"broken\")}" > src/main.rs\
&& cargo build --release
# copy source and rebuild
COPY src/ src/
RUN set -x\
&& find target/release -type f -name "$(echo "${app}" | tr '-' '_')*" -exec touch -t 200001010000 {} +\
&& cargo build --release |
|
@camerondavison adding to your work-around, you can replace pre-last line with: |
|
hey @trezm @camerondavison doesn't work if there are multiple workspaces. |
|
Bummer! Does @vn971's solution work? I don't claim to have any substantial knowledge about cargo, I was just hopefully helping with a workaround :) |
|
@anitnilay20 just copy the needed |
|
@trezm Solution does work for single workspace cargo projects but it doesn't work for multiple workspaces.. |
|
Let's better raise a StackOverflow question or something. This ticket is to add support for the flag. I think multiple workspaces work if done correctly, in the right order. |
|
@vn971 it worked.. issue was bad |
|
Does anyone have a working version that can cache deps for workspaces too? |
|
@dessalines You can check this https://github.com/sha-el/Vouch/blob/master/Dockerfile |
|
@anitnilay20 Thank you so much, that did it! It does re-fetch the workspace deps when anything changes in there, but any changes in the main project don't re-fetch the workspace deps! |
|
I have been dealing with the issue over a year now, both in libs, bins, and workspaces, with projects with and without examples and benches, mostly in docker images. Here are my 2 cents: The underlying consequence is the too high compilation time of slowly-varying code in the context of CI/CD. Specifically, there is a number of rust projects whose majority of their CI/CD time is spent compiling non-changing code, which can be cached (e.g. check logs of arrow/rust or its issues within docker/CI). The core issue is that, in the context of containerization (e.g. docker), engines have no way of knowing that the resulting artifacts in
Cargo supports this locally by not recompiling dependencies that are already compiled. However, it does this because it knows that In theory, solving this issue requires two different API endpoints:
IMO this is issue a sub-part of one of the top 5 requested improvements to rust - compilation time: slow compilation is not only addressed by producing better plans for the LLVM, but also providing the tools to efficiently cache slowly varying code, such as external dependencies. Finally, why the current status quo and "replacing lib.rs/main.rs for a dummy" is not enough: non-workspace projectsThis approach works well for simple projects, but does not work for projects with examples or benches. Essentially, given a workspace projectsWhen there are inter-workspace dependencies, say One current "solution" for this is to repeat the step for non-workspace projects on each workspace including examples/benches (cumbersome). In the end, a command like |
Why you can not use sccache for that? |
We have:
|
In our case we don’t go for sccache because:
Our product consists of multiple components written in different languages. We support this with a small team, so we stick to native tooling and defaults as much as possible. |
|
for those who have the benefit of a buildkit based docker CI process... this is how i've been able to achieve < 1 minute test builds and < 2 minute release builds For Testing:
For release/deployment
|
This allow us to build the crate without having to re-build nor download all its dependencies at the expense of a larger (build) image. Here I am extending the ideas of a non-workspace rust project to a workspace rust project. See [here](rust-lang/cargo#2644) for a _long_ discussion on the issue. Essentially, it is not easy to do this atm with cargo. IMO I think that this is worth it, but I need your help to judge it; it incurs some maintenance (duplication of configurations). Closes #7799 from jorgecarleitao/docker_caching Lead-authored-by: Krisztián Szűcs <szucs.krisztian@gmail.com> Co-authored-by: Jorge C. Leitao <jorgecarleitao@gmail.com> Signed-off-by: Krisztián Szűcs <szucs.krisztian@gmail.com>
|
Having lost more of my life than I care to mention trying to get non-trivial incremental compilation working in something docker-like, I have come to the conclusion that only by removing mtime from the picture can we achieve stable caching. I think we need #6529 to be solved before there's any point in having a command that builds just the dependencies (for which we have reasonable workarounds). Currently there's no way to work around the mtime dependency. |
|
I figured out how to get this also working with cargo workspaces, using romac's fork of cargo-build-deps. This example has
|
|
In python there is a file called
So you dont have to download all dependencies everytime you changes the code. With Rust Im unable to generate compilation cache and build without creating a dummy project. It would be great something like:
Then |
|
@uselessscat This is why I created #8362 , I believe that's more or less what you mean... |
|
As mentioned in #8362, I believe FROM rust as planner
WORKDIR app
RUN cargo install cargo-chef
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM rust as cacher
WORKDIR app
RUN cargo install cargo-chef
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 --from=cacher /app/target target
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"]It does not require Buildkit. |
|
@LukeMathWalker this is much cleaner to have the recipe planning inside docker as well... you should make this the default example in the cargo-chef readme. |
|
I thought I did, but it turns I had not pushed the commit to remote |
There should be an option to only build dependencies.