[Idea] Precompiled dependencies

Motivation

Nowadays, dependency compilation still takes a huge part of crate compilation. I've done a few tests on my machine by building a binary crate with a dependency on specific crate but not using it at all. Taking some examples:

actix-web - 84s
wgpu - 46s

This idea workarounds this by allowing people to request to use the pre-built shared version of libraries to achieve very fast build time, if similar usages has happened before.

Reference-level explaination

Introduce an optional boolean attribute into Cargo.toml for each dependencies called precompiled which defaults to false.

When it is set to true, the behavior of building this dependency is this:

  1. If target != host maybe just emit an error.

  2. If it's already prebuilt do nothing. Otherwise prebuilt it in this way:

    a.Temporarily see its crate type as dylib, and build it with target-dir pointing to a temporary directory, copying the resulting artifacts to ~/.cargo/prebuilt/<crate-name-and-svh-hash>/

  3. Copy the artifacts from prebuilt directory back to target-dir as prebuilt-dependencies. Read its metadata and perform linking with the artifacts as usual properly.

This sounds to me al lot like what sccache does

2 Likes

OP isn't talking about distributing prebuilt binaries from some central repository, just making a local collection of dylibs to speed up future compilation.

What you probably want is sccache (which does exactly that, and allows the use of an online shared cache), or even just setting CARGO_TARGET_DIR to a shared directory. The biggest risk is that the build cache grows unboundedly, but if you clean it approximately every six weeks when you update your compiler (and thus will have to rebuild anyway) it stays pretty reasonable.

4 Likes

Is there a reason why it's not done by default?

It's probably only due to practical implementation difficulties, and a matter of fixes and refactorings to make it work properly.

Issues I'm aware of:

  • build products like executables are written to the target dir without any namespacing, so different crates can accidentally overwrite each other. This is already a problem for workspaces, but would be even worse for a "global" directory.

  • Change of features invalidates cache and causes a rebuild, instead of having separate caches for every set of features. If you have several projects sharing same cargo target dir, then building one project may invalidate caches of the previous project.

  • I've tried changing layout of directories inside target/, but cargo had lots of tests that depend on exactly the current layout, and were PITA to update. I suspect cargo clean also makes some assumptions about it, since I broke it and couldn't fix it :slight_smile:

1 Like

Yes it's a little like sccache in principle. I'm not totally familar with sccache itself, but the biggest difference on my mind is that, sccache still follows existing rustc invocations and caches rlibs. The proposal here instead bundles the dependency subtree into linked shared libraries (sos or dylibs), and cut down linking time a lot too by sacrificing binary size and link quality. (Some crates has already been suggesting using dylib version for casual development now).

This is meant as a comparable mechanism to cargo install but for libraries.