File Naming and Module Organization

I can't find the rules for how cargo finds files and determines what files to build as part of a package. A generated Cargo.toml might look like:

[package]
name = "foo"
version = "0.1.0"
edition = "2024"

[dependencies]

There is no mention of files in this manifest. What files get scooped up when I issue cargo build? Can I point cargo at some directory, or do I have to be located in the same directory where Cargo.toml exists?

Does main need to exist in a particular file? Is main part of a module? Do I have to do something to make a library module or is it just a package that doesn't contain main? It seems like module names come from the file names, but it also seems like you can use mod whatever { ... } to stick things in a module, so I'm not sure how things work with regard to scoping.

I'm confused and the documentation is chatty and I'm looking for a specification I guess, but perhaps someone can point me at something that explains these things?

Thanks,

Cargo looks in a very short list of places for entry points. All module structure is ultimately rooted in one of the files described in that document.

1 Like

There are two similar but slightly different things here, which are almost but not quite the same thing: Cargo targets, and crates. These are both not the same thing as modules.

A crate is an entity in the Rust language; it's the compilation unit of Rust; the thing that rustc processes exactly one of when it is run. Crates matter in the language for things like the orphan rule and crate:: paths. A crate is defined by a single “crate root” source file, but may include other files the root file references. A crate compilation can produce either a library or binary; if binary, then a fn main() must be defined in the crate root file.

Cargo targets are essentially declarations of crates; they are often created automatically from the presence of files, but you can also declare them in Cargo.toml, and they are what you can name on the command line when you are asking Cargo to build something. (Cargo targets are not quite 1:1 with crates, because, for example, “the unit-tests of the binary” are a separate crate from “the binary” and this matters sometimes.)

By default, and in most published Rust code, Cargo’s “target auto-discovery” defines crates based on files. Unfortunately, it's not really rigorously documented; that page and the Package Layout page are the best documentation available. The way I would explain it is: a target (and hence, at least one crate) is automatically defined whenever one of the following filenames is found:

src/lib.rs
src/main.rs
src/bin/*.rs
src/bin/*/main.rs
benches/*.rs
benches/*/main.rs
examples/*.rs
examples/*/main.rs
tests/*.rs
tests/*/main.rs

Every target has a name — it is taken from the part of the path denoted * in this list, or, for src/lib.rs and src/main.rs, defaults to the same name as is declared for the [package].

A module is either the crate root itself or item defined in a crate using the mod keyword. Every source file that is not one of the above crate-root files is brought in to the crate using mod (or include!). For more precise information on crates and modules, see Crates and source files.

Much like Cargo target auto-discovery, rustc has default rules for where module files go, but those operate in the opposite fashion; instead of seeing a file and concluding it should be a module, rustc infers where to look for source based on the name of your mod and its containing module.

5 Likes