How to create a crate with one lib and several bins coexisting?

The Rust book said I can create a module system with only one lib.rs as the crate root, while simultaneously allow several other files, which can be compiled into several executable bins, to co-exist. How can you do that?

I did some tests:
Initially, I defined the module system in main.rs, and used them in the same file as follows:

use crate::backyard::garden::vegetables::asparagus;
use crate::backyard::garden::vegetables::tomatos;
use crate::front_of_house::hosting;
use crate::front_of_house::serving;

fn main() {
    println!("Hello, world!");
    let plant1 = asparagus {};
    println!("I'm growing {:?}!", plant1);
    let plant2 = tomatos {};
    println!("I'm growing {:?}!", plant2);

    hosting::welcome();
    serving::serve();
    serving::checkout();

    front_of_house::deliver();
}
//the module system section begines here:
mod backyard;

mod front_of_house {
  pub fn deliver() {
    hosting::welcome();
    serving::serve();
    serving::checkout();
  }
  pub mod hosting {
    fn add_to_waitlist() {}
    fn sit_at_table() {}
    pub fn welcome() {
      add_to_waitlist();
      sit_at_table();
    }
  }

  pub mod serving;
}
//the module system section ends here:

All the mod are well defined in other files, and the code can be compiled and run smoothly.

And then, I decided to change it to lib:
I moved the "module system section" into a new file and named it lib.rs, and rename main.rs into haha.rs, and then run cargo build, which is OK, smoothly compiled out a "project_name.rlib" file in the traget folder.

But the problem is:
1: I cannot remain the file main.rs using its original file name main.rs, I have to change it to some other names (haha.rs here), otherwise, it won't compile. The error messages are all about "could not find something in the crate root:

error[E0433]: failed to resolve: could not find `backyard` in the crate root
  --> src/main.rs:41:12
   |
41 | use crate::backyard::garden::vegetables::asparagus;
   |            ^^^^^^^^ could not find `backyard` in the crate root

error[E0433]: failed to resolve: could not find `backyard` in the crate root
  --> src/main.rs:47:12
   |
47 | use crate::backyard::garden::vegetables::tomatos;
   |            ^^^^^^^^ could not find `backyard` in the crate root

error[E0432]: unresolved import `crate::front_of_house`
  --> src/main.rs:49:12
   |
49 | use crate::front_of_house::hosting;
   |            ^^^^^^^^^^^^^^ could not find `front_of_house` in the crate root

error[E0432]: unresolved import `crate::front_of_house`
  --> src/main.rs:50:12
   |
50 | use crate::front_of_house::serving;
   |            ^^^^^^^^^^^^^^ could not find `front_of_house` in the crate root

error[E0433]: failed to resolve: use of undeclared crate or module `front_of_house`
  --> src/main.rs:64:5
   |
64 |     front_of_house::deliver();
   |     ^^^^^^^^^^^^^^ use of undeclared crate or module `front_of_house`

I guess, what happend here is: the cargo still treat main.rs as the crate root, and try to find the module system in main.rs. So I changed its name to haha.rs, after which, cargo treat lib.rs as the crate root correctly, and start to compile. But here comes the second problem:

2: Even after I changed to the haha.rs, I didn't get any executable bin files related to haha. Actually, I didn't get any executable bins, the code defined in main() is like disappeared.

I cannot even get one lib and one bin to co-exist. How to do that?

Further question:
How can I let one lib and several bins to co-exist? Like the book described, define the module system in lib.rs (at least crate root here), and then define some bins as client users in somewhere else.
How to do that? How to write which part at where? And how to choose the file name?

Hope I described the question clearly. Please help out! Thanks.

You need this:

*
| Cargo.toml
+-\ [src]
  + lib.rs
  +-\ [bin]
    + my_bin1.rs
    \ my_bin2.rs

This will generate you 2 binaries: my_bin1 and my_bin2. Both can use contents of lib.rs via project_name:: prefix (project_name is what you used as name in Cargo.toml).

For more on multiple execs from a single project, read this part of The Cargo Book.

4 Likes

Thanks, that works!

Supplement info:
change the use sentence in bin1.rs and bin2.rs from use crate::...; to use project_name::...;
Each of bin1.rs and bin2.rs has a main() function.
write the following to Cargo.toml:

[[bin]]
name = "bin1"
test = false
bench = false

[[bin]]
name = "bin2"
test = false
bench = false

cargo build will generate two executables in target folder: bin1 and bin2.
use cargo run --bin bin1 or cargo run --bin bin2 to run each of them.

You can also just put multiple binaries into src/bin without modifying Cargo.toml.

.
├── Cargo.lock
├── Cargo.toml
└── src/
    ├── bin/
    │   ├── a.rs
    │   └── b.rs
    └── lib.rs
1 Like

That is true. Tested it. Didn't know that!
Thanks!

What's exactly what I proposed :expressionless:

2 Likes

I was clarifying that there's no need to touch Cargo.toml, given their followup post.

2 Likes