How can I specify binary-only dependencies?
I have a crate with both a binary and a library. The library is extremely light on dependencies, while the binary requires quite a bit more to, e.g., load files or do scoped parallel things.
Currently, I have my Cargo.toml set up like this:
[dependencies.kdtree]
path = "../kdtree"
[dependencies]
rand="0.3.0"
rustc-serialize = "0.3"
csv = {git = "https://github.com/BurntSushi/rust-csv.git"}
crossbeam = "0.2"
num_cpus = "0.2"
[lib]
name = "conformal"
path = "src/lib.rs"
[[bin]]
name = "ucitest"
path = "src/bin/main.rs"
The only dependencies the library needs are the kdtree
and rand
. However, it seems like even if you only build the library, it goes and builds the binary-only dependencies anyway. I've tried using features
and other tricks like [[bin].dependencies]
or [ucitest-dependencies]
(or adding a dependencies= []
line under [[bin]]
) that I thought might make them only build for the binary, but I can't find a way.
These aren't enough dependencies to make this a problem, but it's bothering me. Is there a way to narrow down dependencies so they only build for specific binaries?
There are several ways to simulate what you want:
1) Turn the binaries to examples
Examples and tests are built with dev-dependencies
, so you could move those dependencies into this section. The library won't depend on them.
# File structure
conformal/
Cargo.toml
src/
lib.rs
examples/ # <-- the `ucitest` is
ucitest.rs # <-- moved to here
# Cargo.toml
[dependencies]
kdtree = { path = "../kdtree" }
rand = "0.3"
[dev-dependencies] # <-- move the examples-only dependencies here
serde = "1"
csv = "0.15"
crossbeam = "0.3"
num_cpus = "1"
[lib]
name = "conformal"
[[example]] # <--- declare the executable
name = "ucitest" # <--- as an example
To run the binary, use:
cargo run --example ucitest
2) Optional dependencies with required features
Dependencies can be made optional, so other crates that depend on your conformal
library won't need to download them.
Starting from Rust 1.17, binaries can declare they require certain optional features to be turned on, effectively making those libraries "needed only for binaries".
# Cargo.toml
[dependencies]
kdtree = { path = "../kdtree" }
rand = "0.3"
serde = { version = "1", optional = true } # <-- make
csv = { version = "0.15", optional = true } # <-- all of
crossbeam = { version = "0.3", optional = true } # <-- them
num_cpus = { version = "1", optional = true } # <-- optional
[lib]
name = "conformal"
[features]
build-binary = ["serde", "csv", "crossbeam", "num_cpus"]
[[bin]]
name = "ucitest"
required-features = ["build-binary"] # <--
Note that you need to manually pass --features build-binary
when building the binaries:
cargo run --features build-binary --bin ucitest
3) Make the binaries as its own package
You could do whatever dependency management you like when the library and the binary are separate packages.
# File structure
conformal/
Cargo.toml
src/
lib.rs
ucitest/ # <-- move ucitest
Cargo.toml # <-- into its own
src/ # <-- package.
main.rs
# ucitest/Cargo.toml
[dependencies]
conformal = { version = "0.1", path = "../" } # <-- explicitly depend on the library
serde = "1"
csv = "0.15"
crossbeam = "0.3"
num_cpus = "1"
These days this is probably best solved with workspaces [1, 2].
The directory structure is as follows:
project-root
├── Cargo.lock
├── Cargo.toml
├── yourlibary
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── src
│ └── main.rs
└── target
The top-level Cargo.toml
file:
[package]
name = "yourprogram"
version = "0.1.0"
authors = ["You <[email protected]>"]
[workspace]
[dependencies]
yourlibrary = { path = "yourlibrary" }
yourlibrary
Cargo.toml
file:
[package]
name = "yourlibrary"
version = "0.1.0"
authors = ["You <[email protected]>"]
[dependencies]
The Cargo.lock
file as well as the target
directory is at the project root directory and is shared by all the components in the workspace. Workspace components are inferred automatically from dependencies with locak path, but can be specified manually as well.
Each component with its Cargo.toml
file can still be published separately on crates.io