How to define a multi level crate? - rust

I'm trying to define the crate going along with my Rust application as explained in the documentation. Let's take the following directory structure:
src/
├─ lib.rs
├─ main.rs
└─ myapp/
├─ a/
│ ├─ a1.rs
│ └─ mod.rs
└─ mod.rs
Now I defined the following in my rust files:
lib.rs
pub mod myapp;
main.rs
extern crate myapp;
use myapp::a;
fn main() {
unimplemented!();
}
myapp/mod.rs
pub mod a;
myapp/a/mod.rs
pub use self::a1::*;
mod a1;
myapp/a/a1.rs
pub fn myfunc()
{
unimplemented!();
}
If I try to compile the above directory tree, I got the error:
$ cargo build
Compiling myapp v0.1.0
src/main.rs:2:5: 2:13 error: unresolved import `myapp::a`. There is no `a` in `myapp` [E0432]
src/main.rs:2 use myapp::a;
^~~~~~~~
src/main.rs:2:5: 2:13 help: run `rustc --explain E0432` to see a detailed explanation
error: aborting due to previous error
Could not compile `myapp`.
Where am I wrong here? I think I have the same directory structure as the one shown in the documentation.

You've added an extra level of nesting. Your main works if you change it to be
extern crate myapp;
use myapp::myapp::a;
fn main() {
unimplemented!();
}
Crates form their own level in the path, so the first myapp refers to the crate, the second myapp refers to the module you've created.
On a side note, it's rare to see a crate with this level of nesting and bifurcation. Rust crates tend to have larger chunks of code per file, and certainly not the one-struct-per-file that is common in other languages. This is all in my experience, of course, and isn't a hard-and-fast rule.

Related

error[E0601]: `main` function not found in crate for utilitary file for a custom binary

I have a custom binary called cli.rs and a file clap.rs with some utilities for clap.rs:
src
bin
cli.rs
clap.rs
where clap.rs just provides me with the clap definitions:
pub fn get_matches() -> ArgMatches {
}
fn main() {}
so I can import them into cli.rs.
However if I take out fn main from clap.rs I get
error[E0601]: `main` function not found in crate `clap`
I don't want clap.rs to have a main function, I just it to simply be a utils file for the binary cli.rs
From the cargo book about package layout:
Cargo uses conventions for file placement to make it easy to dive into a new Cargo package:
.
// ...
├── src/
| | // ...
│ └── bin/
│ ├── named-executable.rs
│ ├── another-executable.rs
│ └── multi-file-executable/
│ ├── main.rs
│ └── some_module.rs
| // ...
[...]
The default executable file is src/main.rs.
Other executables can be placed in src/bin/.
[...]
If a binary, example, bench, or integration test consists of multiple source files, place a main.rs file along with the extra modules within a subdirectory of the src/bin, examples, benches, or tests directory. The name of the executable will be the directory name.
By putting both cli.rs and clap.rs into bin/, you told Cargo that you have two binaries: One named cli, one named clap.
This package layout should work for you:
src
bin
cli
main.rs (that's your cli.rs)
clap.rs
Alternatively, you could also put clap.rs into a lib crate (by putting it inside lib/ and then putting pub mod clap; inside lib.rs). Note however that you then need to reference get_matches() as <your_package_name>::clap::get_matches() so that the compiler knows you are not referencing something from your binary crate, but something from your library crate.

rust modules resolution from main.rs

I have a question about rust modules resolution.
It seems to be that inside crate modules I can reference the other modules using crate name or crate/super/self keywords.
but in main.rs I can only use modules with crate name?
Am I doing something stupid here?
My project:
$ tree
.
├── Cargo.toml
└── src
├── add2.rs
├── add.rs
├── lib.rs
└── main.rs
Cargo.toml content:
[package]
name = "example"
....
main.rs content:
use example::add::{add_one};
fn main() {
println!("{}", add_one(1));
}
lib.rs content:
pub mod add;
add.rs content:
pub fn add_one(x: i32) -> i32 {
x + 1
}
add2.rs content:
use crate::add::{add_one};
pub fn add_two(x: i32) -> i32 {
add_one(add_one(x))
}
Am I doing something stupid here?
No, it`s just that Cargo adds one more layer of complexity called the "package", for better or worse, which makes it more confusing.
In short, your Cargo package contains two Rust crates: the binary one and the library one. When you are in main.rs, the example library crate is an external dependency like any other... which means you aren`t in the same crate!
Crate roots such as main.rs, lib.rs, bin/other_root.rs, etc. are treated differently by the module system. When they refer to module files they are referring to files in the root of the src/ directory only. In the normal case mod refers to files in the root of a local sub-directory with the same name as the containing file, mirroring the unique container constraint of the inline module layout as well as the file system hierarchy (barring linked files, of course). In essence, crate roots treat src/ as their local sub-directory as far as mod is concerned.
I gave perhaps a more wordy explanation here

Correct place for private module to be used by multiple executables

Two executables' sources, foo.rs and bar.rs, are located in src/bin.
Private common functionality exists in src/bin/common.rs.
foo.rs and bar.rs include this functionality with:
mod common;
use common::{Bish, Bash, Bosh};
This works, but src/bin/common.rs doesn't feel like the right path for something which isn't going to be built into an executable.
Moving common.rs to src or src/lib stops foo.rs and bar.rs from seeing it.
Where should I put common.rs and how do I then import it?
A common approach to store shared parts at lib.rs and use these in binaries. Its usage, though, is a bit different than simply mod + use. In fact, library is a separate crate, so you need to access it via crate name (defined in Cargo.toml).
Cargo.toml:
[package]
name = "crate-name"
# ... the rest
src/bin/foo.rs:
fn main() {
crate_name::fun();
}
src/lib.rs:
pub fn fun() {}
example
├── Cargo.toml
└── src
├── bin
│   ├── bar.rs
│   └── foo.rs
├── common.rs
└── lib.rs
foo.rs and bar.rs:
#[path = "../common.rs"]
mod common;
use common::{Bish, Bash, Bosh};
also see: How can I use a module from outside the src folder in a binary project, such as for integration tests or benchmarks?

"Unresolved import" when linking with [lib] in Cargo.toml [duplicate]

I'm trying to create a module in Rust and then use it from a different file. This is my file structure:
matthias#X1:~/projects/bitter-oyster$ tree
.
├── Cargo.lock
├── Cargo.toml
├── Readme.md
├── src
│   ├── liblib.rlib
│   ├── lib.rs
│   ├── main.rs
│   ├── main.rs~
│   └── plot
│   ├── line.rs
│   └── mod.rs
└── target
└── debug
├── bitter_oyster.d
├── build
├── deps
├── examples
├── libbitter_oyster.rlib
└── native
8 directories, 11 files
This is Cargo.toml:
[package]
name = "bitter-oyster"
version = "0.1.0"
authors = ["matthias"]
[dependencies]
This is main.rs:
extern crate plot;
fn main() {
println!("----");
plot::line::test();
}
This is lib.rs:
mod plot;
this is plot/mod.rs
mod line;
and this is plot/line.rs
pub fn test(){
println!("Here line");
}
When I try to compile my program using: cargo run I get:
Compiling bitter-oyster v0.1.0 (file:///home/matthias/projects/bitter-oyster)
/home/matthias/projects/bitter-oyster/src/main.rs:1:1: 1:19 error: can't find crate for `plot` [E0463]
/home/matthias/projects/bitter-oyster/src/main.rs:1 extern crate plot;
How do I compile my program? As far as I can tell from online documentations this should work, but it doesn't.
To add to the given answers, a library compiled as a cdylib (docs) can generate this error when you try to reference it in another project. I solved it by separating the code I wished to reuse in a regular lib project.
If you see this error:
error[E0463]: can't find crate for `PACKAGE`
|
1 | extern crate PACKAGE;
| ^^^^^^^^^^^^^^^^^^^^^ can't find crate
it could be that you haven't added the desired crate to the dependencies list in your Cargo.toml:
[dependencies]
PACKAGE = "1.2.3"
See specifying dependencies in the Cargo docs.
You have the following problems:
you have to use extern crate bitter_oyster; in main.rs, because the produced binary uses your crate, the binary is not a part of it.
Also, call bitter_oyster::plot::line::test(); in main.rs instead of plot::line::test();. plot is a module in the bitter_oyster crate, such as line. You are referring to the test function with its fully qualified name.
Make sure, that every module is exported in the fully qualified name. You can make a module public with the pub keyword, like pub mod plot;
You can find more information about Rust's module system here: https://doc.rust-lang.org/book/crates-and-modules.html
A working copy of your module structure is as follows:
src/main.rs:
extern crate bitter_oyster;
fn main() {
println!("----");
bitter_oyster::plot::line::test();
}
src/lib.rs:
pub mod plot;
src/plot/mod.rs:
pub mod line;
src/plot/line.rs :
pub fn test(){
println!("Here line");
}
I got this issue when I had imported my crate in [dev-dependencies] instead of [dependencies]
This can also happen when you don't enable certain "feature flags" for specific crates. Unfortunately, these feature flags can sometimes be undocumented. When feature flags are missing when required, they show the same error ("Can't find crate")
I was using diesel, and was trying to use BigInteger:
Wrong
diesel = { version = "2.0.3", features = ["postgres", "chrono", "r2d2", "serde_json", "biginteger"] }
Correct:
diesel = { version = "2.0.3", features = ["postgres", "chrono", "r2d2", "serde_json", "numeric"] }

Importing non-root module from multiple non-root binaries

I am learning Rust and decided to write a simple client/server program. Both the client and the server will be using a very simple module I've already written. Knowing that this code might grow, I decided to compartmentalize my source for clarity. Right now my current hierarchy looks as follows:
├── Cargo.lock
├── Cargo.toml
├── README.md
├── src
│   ├── client
│   │   └── main.rs
│   ├── common
│   │   ├── communicate.rs
│   │   └── mod.rs
│   ├── lib.rs
│   └── server
│   └── main.rs
Many of the examples I found on Stack Overflow and the net provide great samples for when the main.rs is in the project root directory. Unfortunately I'm trying to do something different as shown above.
communicate.rs contains all of the network code I have written. Eventually I will add other Rust files here and include their public mod statement in mod.rs. Currently common/mod.rs all I have is
pub mod communicate;
Focusing on just the client folder, all I have is main.rs as shown. The file "header" lists
extern crate common;
use std::thread;
use std::time;
use std::net;
use std::mem;
use common::communicate;
pub fn main() {
// ...
}
Besides the fundamental [package] section, all I have in Cargo.toml is
[[bin]]
name = "server"
path = "src/server/main.rs"
[[bin]]
name = "client"
path = "src/client/main.rs"
When I try to build the client binary, the compiler complains that the common crate could not be found.
$ cargo build
Compiling clientserver v0.1.0 (file:///home/soplu/rust/RustClientServer)
client/main.rs:1:1: 1:21 error: can't find crate for `common` [E0463]
client/main.rs:1 extern crate common;
^~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
error: Could not compile `clientserver`.
To learn more, run the command again with --verbose.
I think this is because it is looking for a common crate within the client/ folder. I had this same problem when I tried the mod statement instead of extern crate statement.
use std::thread;
use std::time;
use std::net;
use std::mem;
mod common;
Gave me:
client/main.rs:6:5: 6:11 error: file not found for module `common`
client/main.rs:6 mod common;
^~~~~~
client/main.rs:6:5: 12:11 help: name the file either common.rs or common/mod.rs inside the directory "client"
I also tried (using the extern crate...) adding a lib.rs in the client whose contents are pub mod common; but I still get the same error as the first.
One potential solution I found to model it like this project, but this would require a Cargo.toml in every folder, something which I'd like to avoid.
I feel like I am close but am missing something.
You are not building common as a crate right now. The crates being built are the library clientserver (the default name for the library is the package name) and the binaries client and server.
Normally, extern crate clientserver; should work. However, if you want to name your library differently, you can do so by specifying a different name in a [lib] section in Cargo.toml. In this section, you can also specify a different source path for the library's main source file. In your case, it will probably be better, otherwise you'll end up with a crate named common and all of its contents would be in a module named common, so you'd have to access everything as common::common::foo. For example, by adding this to your Cargo.toml:
[lib]
name = "common"
path = "src/common/lib.rs"
you could combine src/lib.rs and src/common/mod.rs into src/common/lib.rs. Then, extern crate common; should work in your binaries.

Resources