14
votes

Right now I have a Cargo workspace with three members.

[workspace]
members = [
    "foo",
    "bar",
    "baz",
]

If I run cargo run in the root directory, I get this error:

error: manifest path /home/lukas/dev/mahboi/Cargo.toml is a virtual manifest, but this command requires running against an actual package in this workspace

That makes sense. I can run cargo run -p foo and it works. But the thing is: foo is the only crate that is executable and I will execute it very often, so it would be nice if I could just run cargo run and execute it.

I tried to use the default-members key, but this didn't help:

default-members = ["foo"]

Is there another way to tell Cargo that cargo run should execute the foo crate (equivalent to running cargo run in the foo/ subdirectory)? I would also accept answers that make the root crate non virtual (i.e. add a [package] key).

1
I've also been looking for this. I know that you can at least do cargo run -p foo to use package foo every time you run cargo run. There's also the option to have your top-level folder be both a crate, and a workspace for nested crates, but I didn't go that route, as it adds more confusion. I'd also like to see me being able to set the default binary crate at the virtual manifest level.JeanMertz

1 Answers

13
votes

Single Binary

This is available as of Rust 1.30. Here is the complete set of files I tested with:

Cargo.toml

[workspace]
members = [
    "foo",
    "bar",
    "baz",
]

foo/Cargo.toml

[package]
name = "foo"
version = "0.1.0"
authors = ["An Devloper <[email protected]>"]

[dependencies]

foo/src/main.rs

fn main() {
    println!("Hello, world!");
}

bar/Cargo.toml

[package]
name = "bar"
version = "0.1.0"
authors = ["An Devloper <[email protected]>"]

[dependencies]

bar/src/lib.rs

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}

baz/Cargo.toml

[package]
name = "baz"
version = "0.1.0"
authors = ["An Devloper <[email protected]>"]

[dependencies]

baz/src/lib.rs

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
$ tree .
.
├── Cargo.lock
├── Cargo.toml
├── bar
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── baz
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── foo
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── src
│   └── lib.rs
└── target
    └── ...
$ cargo run
   Compiling baz v0.1.0 (file:///private/tmp/example/baz)
   Compiling bar v0.1.0 (file:///private/tmp/example/bar)
   Compiling foo v0.1.0 (file:///private/tmp/example/foo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.39s
     Running `target/debug/foo`
Hello, world!

Multiple Binaries

As of Rust 1.37.0 you can use Cargo's "default-run" feature to specify which one to use.

foo/Cargo.toml

[package]
name = "foo"
version = "0.0.1"
authors = ["An Devloper <[email protected]>"]
default-run = "foo"