Is it a good idea to have one crate with [[bin]] and [lib]?


#1

I agree with the approach previously recommended here that you rather than building just a binary, you should have a binary that does just main and arg parsing, and calls into a library. (This is specifically in the context of https://github.com/sourcefrog/conserve.)

It seems like the natural way to do this in Rust is with a single crate that provides both a [[bin]] and library section.

But then, doing that seems fairly imperfectly supported across the Rust ecosystem: for example cargo-check won’t work on such crates, and nor will Clippy. (Actually perhaps these have the same underlying cause in rustc or cargo?)

So my questions are:

  • Would I be better off refactoring one into a sub-crate or a separate standalone crate? If so, which? I would really like cargo install conserve to work to install the command-line tool.

  • Maybe the Rust book, or the Cargo documentation, or the Rust guide (maybe here?) could give some guidance on this?


#2

These are just bugs in those crates, and should be fixed.

(And in the meantime, it seems to be that they do work; you just need to pass --bin or --lib, but that’s my impression from reading the issues; I have not tried it.


#3

Not exactly. The problem with cargo-check is quite tricky. cargo-check is actually an alias for cargo rustc -- -Z no-trans but unlike cargo build this command does not compile all targets. I filed an issue for this in the Cargo repo but it won’t be changed because:

Cargo doesn’t know what’s getting passed to the compiler, so it has no idea if the compiler actually generates an appropriate output. As a result it can’t know whether the binary in this case can actually depend on the library because the library may not be generated with a special set of flags.

But the problem is that cargo-check is mostly used for fast feedback in editor linters. For example the Atom Rust linter has an option to use cargo build or cargo-check for linting. cargo-check is way faster because it doesn’t have to generate anything, just perform the analysis. So you would want to use cargo-check over cargo build for faster error reporting. But unfortunately you can’t when you have both a binary and a library in the same crate, which is common practice in Rust.

I am pretty confident that this is the exact scenario the OP is running into.


#4

Yes, that’s the problem.


#5

From my experience this is all pretty poorly supported. The same goes for examples. In particular features and depedencies are not handled very flexibly. The library, the binaries and the examples will all have the same dependencies and features configured. This means that if you only need some dependencies for your binaries or examples, users of your library will still need to compile those dependencies every time. Also, if your binaries or examples need to use a particular feature in a dependency, this feature must also be enabled for building the library. Again, this shows up when other people use your library. All in all, I’d recommend having a seperate -bins or -examples crate.