Rust tip and trick — organize project 1 Link to heading
If you want to start a Rust project, you might be tempted to run the cargo command like this:
$ cargo new my_awesome_project
Created binary (application) `my_awesome_project` package
This creates a simple binary boilerplate project with a single source file src/main.rs.
$ tree my_awesome_project/
my_awesome_project/
|-- Cargo.toml
`-- src
`-- main.rs
This is probably fine if you are just learning Rust or experimenting with some ideas. However, for a more serious project, this is not an ideal structure. A better way to organize the project is to separate the source files into a binary and a library. This way, you can reuse the library code in different binaries or even publish it as a crate. To achieve this, you need a slightly different cargo command:
$ cargo new --lib my_awesome_project
Created library `my_awesome_project` package
This creates a library project without any binary. To add binary files, you simply need to manually create a src/bin folder and put any Rust source file in there. Cargo will automatically recognize them as binaries and compile them accordingly.
$ cd my_awesome_project
$ mkdir src/bin
$ echo 'fn main() { println!("binary1"); }' > src/bin/binary1.rs
$ echo 'fn main() { println!("binary2"); }' > src/bin/binary2.rs
$ tree
.
|-- Cargo.lock
|-- Cargo.toml
`-- src
|-- bin
| |-- binary1.rs
| `-- binary2.rs
`-- lib.rs
$ cargo build
Compiling my_awesome_project v0.1.0 (my_awesome_project)
Finished dev [unoptimized + debuginfo] target(s) in 0.27s
$ cargo run --bin binary1
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/binary1`
binary1
$ cargo run --bin binary2
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/binary2`
binary2
So far, we have created a library project and added binary files, but haven’t actually linked them yet. In order for the binary files to access library functions, we just need to declare use my_awesome_project in the binary source files. For example, the boilerplate src/lib.rs has add() function:
pub fn add(left: usize, right: usize) -> usize {
left + right
}
To use this function from the binary files, we modify, say src/bin/binary1.rs as follows:
use my_awesome_project::add;
fn main() {
println!("1 + 2 = {}", add(1, 2));
}
Now, we can run the binary1 file and confirm that it can indeed import from the library
$ cargo run --bin binary1
Compiling my_awesome_project v0.1.0 (my_awesome_project)
Finished dev [unoptimized + debuginfo] target(s) in 0.13s
Running `target/debug/binary1`
1 + 2 = 3
There exist more advanced methods to separate the binary and library source files, such as using workspace. I will cover that in a later story, so stay tuned!