Pros and cons of splitting out crates


#1

Should I split my project up into lots of small crates (that may be useful externally), a la node/npm, or are there disadvantages to doing so? What kind of optimisations can (or can’t) rustc do across crates?


#2

On a conceptual level, I like my code modular and reusable. So, I’ll try to create a lot of small crates. Since you can have multiple crates in one repository, it’s very cheap to divide early and move crates into their own repo when they expand. This also let’s you track dependencies on a more granular level.

Here’s a bit of motivation (by someone who published over 600 modules to npm): http://dailyjs.com/2015/07/02/small-modules-complexity-over-size/ (tl;dr don’t need to remember as much, tests, every projects profits from optimizations to basic crates)

AFAIK, there are some difficulties with inlining across crates; but there is also stuff with LTO which sometimes helps but is other times considered bad.


#3

Don’t forget that since crates are the compilation unit, more and smaller crates means that you’re getting a more paralell compile.


#4

One of the disadvantages of splitting a crate into smaller crates is that there isn’t function inlining across crates without #[inline], so possibly less optimization.


#5

That’s a good tip though: explicit #[inline] works across crates!


#6

Also note that generic functions and blanket trait implementations can be inlined across traits without any explicit annotations.


#7

A question, if I embed a crate in another (use dependency with path = "xyz" how does cargo and crates.io treat that? Is it possible to publish the crate with a bundled dependency like this? I’ve never tried.


#8

Yes. regex does this for regex-syntax: https://github.com/rust-lang/regex/blob/master/Cargo.toml#L39