How to refer to a sibling module from binary?

Hello,

I'm trying to produce multiple binaries and want to group those under src/api so my Cargo.toml looks like:

...
[[bin]]
name = "ts-server"
path = "src/api/server.rs"
...

[[bin]]
name = "ts-foo"
path = "src/api/foo.rs"
...

The directory structure looks like this:

.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── api (/server.rs, /foo.rs)
│   └── parsing (/mod.rs)
│   └── others (/mod.rs)

Then from the src/api/server.rs I need to use the parsing module and this is what I can't understand how.

  • when the server.rs is located in src/server.rs - can refer to the module by mod parsing (and the appropriate use-s)
  • when the server.rs is located in src/api/server.rs - the parsing module cannot be referred to anymore because:
// src/api/server.rs

// error[E0583]: file not found for module `parsing`
//  --> src/api/server.rs:21:5
//   |
// 21 | mod parsing;
//   |      ^^^^^^^
//   |
//   = help: name the file either parsing.rs or parsing/mod.rs inside the directory "src/api"
mod parsing;

So my question is how do I get hold of sibling modules in relation to the api?
Thanks.

1 Like

The canonical (I believe) way to set this up would be:

.
├── Cargo.lock
├── Cargo.toml 
├── src
     ├── bin
     │   ├── server.rs
     │   ├── foo.rs
│   └── parsing (/mod.rs)
│   └── others (/mod.rs)
│   ├── lib.rs

You put your binaries into the bin directory, and add a lib.rs to the crate root. The net result is you have a library crate, and the binaries make use of like an extern crate.

In your lib.rs you'd export the modules as necessary, e.g.:

pub mod parsing;

In server.rs you'd start off with:

extern crate <your_crate_name>;
use <your_crate_name>::parsing;
2 Likes

What @vitalyd said, except that the binary source files should be in src/bin

Oops, yes - fixed, thanks!

It's not strictly necessary to put it under src/ (although no reason to deviate), but Cargo automatically knows that src/bin/... contains binaries. Otherwise, you can put them elsewhere and note them with the [[bin]] section, as in the OP.

The typical project layout is detailed in the Cargo reference.

Thanks, that makes sense.

But why is that I need to create a lib.rs when the binary files are in a subdirectory (such as src/bin) and I don't need to do it when the binary files are just in the roo of src?

If the binary is in the root of src/, the binary itself is the crate root module and declaring mod parser; in it is the standard way of telling rustc about the child modules contained in the crate. If you move the binary to a subdirectory, then I don't think module resolution, from the root module, can go upwards in the directory structure.

But in general, defining binaries that are essentially consumers of your library crate has some benefits. Not only is the separation clearer (IMO), but it also gives you the perspective of your would-be lib consumers (even if none today, perhaps some in the future) and so you can see how it feels to work with your lib "externally".

Thanks for the help. Appreciate it.

Is it correct to say that when I point [[bin]]'s path to the root (src) then the whole codebase is a crate.
And if there are 2 bins then the those get compiled twice as 2 separate crates that just happen to share the same codebase?

Also, you can save on compile time since the library component is only compiled once.

1 Like