main.rs
main2.rs
file1.rs
src/something.rs
Cargo.toml
on main.rs, doing mod file1 works, but doing mod file1 on main2.rs leads to
file not found for module `file1`
Why only main.rs can declare sibling files with mod?
New modules can be declared from both main.rs and lib.rs. The first is used for binary crates, the latter - for libraries. It's important to note that if a package has both files, then it will have two crates with the same name (one library and one binary). You can also have multiple binary crates, if you define the crate roots (explained below) in src/bin - each file will be treated as a separate binary crate. This is explained in detail in the rust book.
These two files are special - they are called crate roots, because they form a tree-like structure. Each module should be part of it. You cannot define a module outside that tree. This is again explained in the book.
Thus in order to be able to define a new module from within main2.rs, it either has to be a crate root - i.e. it has to have a main() and be located in /src/bin/main2.rs or it has to be part of the module-tree, descending from some of the crate roots.
Related
This question already has answers here:
How do I do a basic import/include of a function from one module to another in Rust 2015?
(3 answers)
Split a module across several files
(7 answers)
How can I include a module from another file from the same project?
(6 answers)
Closed 5 years ago.
How do I include a file with the full path my_project/src/include_me.rs in main.rs?
I've checked the dependencies guide, and all of them appear to be including a binary. I've also checked "The Book", but none of the examples there end in ".rs" either.
How do I make include_me.rs compile with the rest of the project?
There are basically two (main) ways in Rust to include code from somewhere else:
1. "Including" internal code
If your include_me.rs belongs to your project, you should move it to the same folder main.rs lies in:
└── src
├── include_me.rs
└── main.rs
Then you can write this in your main.rs:
mod include_me;
fn main() {
// Call a function defined in the other file (module)
include_me::some_function();
}
A mod declaration makes the Rust compiler look for the corresponding .rs files automatically!
So everything that belongs to your project, belongs in the same folder (or a subfolder thereof) as the folder where main.rs (or lib.rs) is lying. The files are then "included" via the module system. To read a good introduction into modules, please read the chapter on modules in the Rust book. You could also check out Rust by Example on that topic. The module system is pretty central and thus important to learning Rust.
2. "Including" external code
If your include_me.rs is something that doesn't belong to your actual project, but is rather a collection of useful things you are using in multiple projects, it should be seen as a library. To include code of such external libraries, you have to include it as an extern crate. And to make your life easier, you really want to use Cargo!
So let's prepare your include_me.rs as Cargo library project. You need the following file structure (which is automatically generated by cargo new my_library --lib):
. my_library
├── Cargo.toml
└── src
└── lib.rs
Now copy all the contents from include_me.rs into lib.rs (it is just convention to call the root file of a library project lib.rs). Let's say that the my_library folder's full path is ~/code/my_library.
Now let's prepare your main project's Cargo project. It has a similar file
structure (but a main.rs instead of lib.rs, because it's a executable-project, not a library-project):
. my_project
├── Cargo.toml
└── src
└── main.rs
To declare your dependency on my_library, you have to put this into your Cargo.toml:
[package]
name = "my_project"
version = "0.1.0"
authors = ["you"]
edition = "2018"
[dependencies]
my_library = { path = "~/code/my_library" }
You can also use relative paths ("../my_library"), but it only makes sense if you know that the two projects always stay where they are, relative to one another (like if they are both managed in the same repository).
Now you can, in your main.rs, write:
use my_library::some_function;
fn main() {
// Call a function defined in the other file (extern crate)
some_function();
}
If you want to upload any of those two projects, you have to interact with crates.io (or another crates registry, if your company has one), but this is another topic.
(Note: some time ago, it was necessary to write extern crate my_library; inside main.rs. This is not necessary anymore, but you might find old code with extern crate declarations.)
Any other ways?
Yes, but you shouldn't use those. There is the include!() macro which allows you to verbatim include other files, just like the #include from C-land. However, it is strongly discouraged to use this in situations where the module system would be able to solve your problem. include!() is only useful in very special situations, often linked to a more complex build system which generates code.
I have read Managing Growing Projects with Packages, Crates, and Modules, but I still don't really understand the hierarchy. I know what is crate and that there should be at least one crate in package: max 1 library crate and 0 or more binary crates.
First: Assume I want to have both lib.rs and main.rs crates in package. How do I access/call functions from lib.rs in main.rs?
Second: when I create new library with cargo new --lib library-name it creates directory with that name and bunch of files there, the only way I figured out to call functions from that library in src/main.rs is:
mod some_library;
use crate::library_name::library_name::foo;
fn main() {
foo();
}
// Filename: src/library_name.rs
pub mod library_name; // I don't really understand this
// Filename: src/library_name/library_name.rs
pub fn foo() {
// ...
}
where I have the following hierarchy:
- package_name
- src
- library_name
- src
- lib.rs
- Cargo.toml
- library_name.rs
- library_name.rs
- main.rs
- Cargo.toml
Is it necessary for src/library_name.rs to have the same name as src/library_name library? I'm really confused.
It's a hierarchy of three or four levels.
Workspace (optional): At the top there's the workspace. A workspace consists of one or more packages. The Cargo.toml file is special and more or less only lists the workspace members.
Workspaces are optional and used for big projects. Smaller projects with only one package don't need them. In such cases we can ignore workspaces. We have a package at the top and the hierarchy is only three levels deep.
Package: Then there's the package. A package is what haves a real Cargo.toml file. A package can compile to crates.
Crate: A crate is a library or an executable compiled from the package. A library crate has a lib.rs file as a starting point. An executable crate has a main function as a starting point. A package can compile to at most one library and several executables.
Module: Then there are modules. Modules are the hierarchical way how Rust organizes items like struct, enum, functions and others in the source code.
And how to you use this to give items unique names?
Answer: A fully qualified name starts with the package, then a series of module names then finally the item's name.
An example:
serde::de::value::StringDeserializer (see here) has as package serde, as module path de then value then the struct is called StringDeserializer.
And where's the crate?
The package serde has only one crate, the library. If you look at the package's Cargo.toml there are no binaries listed.
(People tend to be confused about packages and crates. Even sometimes I am not precise and say "the serde crate" when I mean the package.)
In short: A package is code under a name (for example serde). A crate is a library or an executable.
I'm am trying to re-export a submodule from another file from a parent module.
Give this file structure,
src/
- lib.rs
- module/
-- mod.rs
-- submodule/
--- mod.rs
...can this be accomplished in a single line?
// mod.rs
mod submodule;
pub use submodule::*;
// something like pub use mod submodule::*;
If I understand correctly, you're asking if the mod and the use can be combined into a single line.
No, there is no allowance for combining a mod with a use. The right way to think about mod is that it defines where the module is located in the module hierarchy. The fact that it also brings the module name into the namespace of the current module, as if you had written use some_module;, is essentially a part of that, since it would be pointless to ever write mod some_module without making it visible in its parent.
If you want to also make additional names available, there is no special syntax for combining it with a mod; you have to use use.
I have following file structure:
main.rs
-- module_a
-- mod.rs
output.rs
In output.rs, I have a function called log_info() and I'd like to call it from module_a/mod.rs.
I can place mod output; in main.rs and after that I can reference it from module_a/mod.rs, but I don't like having to place all my dependencies in main.rs in order to use them in my application.
Is there any way I can reference the output module in module_a/mod.rs without messing with main.rs?
Is there any way I can reference the output module in module_a/mod.rs without messing with main.rs?
No. Each module (including the crate entry point of main.rs or lib.rs) has to explicitly define what modules are its children.
You could move the output module to be a child of module_a, however.
I'm trying to read the code of servo. As an example, I'm looking at this code in layout_task.rs:
use url::Url;
..and I want to know which code this refers to (the answer is rust-url).
Per the Rust reference §6.1.2.2 Use declarations,
the paths contained in use items are relative to the crate root [...]
It is also possible to use self and super at the beginning of a use item to refer to the current and direct parent modules respectively.
All rules regarding accessing declared modules in use declarations apply to both module declarations and extern crate declarations.
The reference (§5 Crates and source files) does not explicitly say what a "crate root" is, but it does share that:
A crate contains a tree of nested module scopes. The top level of this tree is a module that is anonymous [...] The Rust compiler is always invoked with a single source file as input, and always produces a single output crate. The processing of that source file may result in other source files being loaded as modules.
So it seems that to find the crate root that the current file (layout_task.rs) belongs to, we need to figure out what source file rustc is invoked with when building the crate. With Cargo this is specified in Cargo.toml and defaults to src/lib.rs:
[lib]
path = "src/lib.rs"
In my case, here's Cargo.toml and the lib.rs has:
extern crate url;
pub mod layout_task;
So far so good. To find out what the extern crate refers to, we need to look at Cargo.toml again:
[dependencies.url]
version = "0.2"
The cargo docs claim that "Dependencies from crates.io are not declared with separate sections", but apparently they can be... So we look the package up on crates.io: https://crates.io/crates/url