Confusion about module name ambiguity

I'm sure, this problem has been raised 1000 times already, but I think the whole way of module import/usage is not water proof.

I'm having a beginners project creating an executable. main.rs is the main source, including several other mods by mod <name>;. All these files exist in the crate root, ./src directory.

That works fine. Now I thought it would be a good idea to put 99% of my functionality into a lib in order to allow binding with other projects.

So I created a ./src/lib.rs and took over all the mod declarations formerly contained in ./src/main.rs by removing them the same time from main.rs.

Basically my lib.rs looked like so after this op:

mod opts;
mod constants;
mod config;
mod tools;
mod df_imports;
mod api;


pub fn test() {
    
}

I was able to compile the project and as desired an executable and a library was created.

Now - of course I need to use my library from the main app, so I inserted this into main.rs, which right now does not look different from this:

mod lib;

use lib::test;

fn main() {
  test::test();
}

The only fact to include mod lib; in main.rs is sufficient to generate tons of errors of the same kind, I don't even have to use lib::test; or to call a function.

error[E0583]: file not found for module `opts`
 --> src/lib.rs:1:1
  |
1 | mod opts;
  | ^^^^^^^^^
  |
  = help: to create the module `opts`, create file "src/lib/opts.rs"

error[E0583]: file not found for module `constants`
 --> src/lib.rs:2:1
  |
2 | mod constants;
  | ^^^^^^^^^^^^^^
  |
  = help: to create the module `constants`, create file "src/lib/constants.rs"

error[E0583]: file not found for module `config`
 --> src/lib.rs:3:1
  |
3 | mod config;
  | ^^^^^^^^^^^
  |
  = help: to create the module `config`, create file "src/lib/config.rs"

error[E0583]: file not found for module `tools`
 --> src/lib.rs:4:1
  |
4 | mod tools;
  | ^^^^^^^^^^
  |
  = help: to create the module `tools`, create file "src/lib/tools.rs"

error[E0583]: file not found for module `df_imports`
 --> src/lib.rs:5:1
  |
5 | mod df_imports;
  | ^^^^^^^^^^^^^^^
  |
  = help: to create the module `df_imports`, create file "src/lib/df_imports.rs"

error[E0583]: file not found for module `api`
 --> src/lib.rs:6:1
  |
6 | mod api;
  | ^^^^^^^^
  |
  = help: to create the module `api`, create file "src/lib/api.rs"

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0583`.
error: could not compile `dragonfly2`.

To learn more, run the command again with --verbose.

I have no clue, why this happens. I started a new project from scratch and did the same operations, there everything worked...

What chances do I have to come after that? Do I really have to move all my modules to src/lib/(which is not existent yet?)

PS: After having done what was suggested (moving all the mod files to src/lib) I'm now getting the reverse error:

warning: 60 warnings emitted

error[E0583]: file not found for module opts
--> src/lib.rs:1:1
|
1 | mod opts;
| ^^^^^^^^^
|
= help: to create the module opts, create file "src/lib/opts.rs"

error[E0583]: file not found for module constants
--> src/lib.rs:2:1
|
2 | mod constants;
| ^^^^^^^^^^^^^^
|
= help: to create the module constants, create file "src/lib/constants.rs"

error[E0583]: file not found for module config
--> src/lib.rs:3:1
|
3 | mod config;
| ^^^^^^^^^^^
|
= help: to create the module config, create file "src/lib/config.rs"

error[E0583]: file not found for module tools
--> src/lib.rs:4:1
|
4 | mod tools;
| ^^^^^^^^^^
|
= help: to create the module tools, create file "src/lib/tools.rs"

error[E0583]: file not found for module df_imports
--> src/lib.rs:5:1
|
5 | mod df_imports;
| ^^^^^^^^^^^^^^^
|
= help: to create the module df_imports, create file "src/lib/df_imports.rs"

error[E0583]: file not found for module api
--> src/lib.rs:6:1
|
6 | mod api;
| ^^^^^^^^
|
= help: to create the module api, create file "src/lib/api.rs"

error: aborting due to 6 previous errors

For more information about this error, try rustc --explain E0583.
error: could not compile dragonfly2.

To learn more, run the command again with --verbose.
~/Documents/dragonfly2rust $
~/Documents/dragonfly2rust $
~/Documents/dragonfly2rust $ cargo build
Compiling dragonfly2 v0.1.6 (/Users/decades/Documents/dragonfly2rust)
error: couldn't read src/constants.rs: No such file or directory (os error 2)
--> build.rs:4:1
|
4 | mod constants;
| ^^^^^^^^^^^^^^

error: aborting due to previous error

error: could not compile dragonfly2.

To learn more, run the command again with --verbose.
~/Documents/dragonfly2rust $ cargo build
Compiling dragonfly2 v0.1.6 (/Users/decades/Documents/dragonfly2rust)
error[E0583]: file not found for module opts
--> src/lib.rs:1:1
|
1 | mod opts;
| ^^^^^^^^^
|
= help: to create the module opts, create file "src/opts.rs"

error[E0583]: file not found for module constants
--> src/lib.rs:2:1
|
2 | mod constants;
| ^^^^^^^^^^^^^^
|
= help: to create the module constants, create file "src/constants.rs"

error[E0583]: file not found for module config
--> src/lib.rs:3:1
|
3 | mod config;
| ^^^^^^^^^^^
|
= help: to create the module config, create file "src/config.rs"

error[E0583]: file not found for module tools
--> src/lib.rs:4:1
|
4 | mod tools;
| ^^^^^^^^^^
|
= help: to create the module tools, create file "src/tools.rs"

error[E0583]: file not found for module df_imports
--> src/lib.rs:5:1
|
5 | mod df_imports;
| ^^^^^^^^^^^^^^^
|
= help: to create the module df_imports, create file "src/df_imports.rs"

error[E0583]: file not found for module api
--> src/lib.rs:6:1
|
6 | mod api;
| ^^^^^^^^
|
= help: to create the module api, create file "src/api.rs"

error: aborting due to 6 previous errors

For more information about this error, try rustc --explain E0583.
error: could not compile dragonfly2.

To learn more, run the command again with --verbose.

Does that make any sense?

I could be wrong, but I think that should actually be extern crate my_crate_name, and use my_crate_name::test.

Since Rust 2018 you don't even need the extern crate. Just use the crate name.

2 Likes

Right, this is what I thought too.

I have now created an empty ./src/t1.rs and was able to compile the project.

./src/lib.rs:

mod t1;

pub fn f() {
    println!("Test");
}

But same story: If I import my lib in main.rs, t1 cannot be found anymore from lib

:((

error[E0583]: file not found for module t1
--> src/lib.rs:2:1
|
2 | mod t1;
| ^^^^^^^
|
= help: to create the module t1, create file "src/lib/t1.rs"

error: aborting due to previous error

For more information about this error, try rustc --explain E0583.
error: could not compile dragonfly2.

To learn more, run the command again with --verbose.

What drives me crazy a bit is the fact, that I can do the same operations on a fresh project w/o problems....

You must still have mod lib in your main.rs

I have that....

Do me a favour please. Would you mind to follow me on a test?

  1. cargo new lib-test && cd lib-test && cargo run

Output should be

Hello, world!

  1. touch ./src/test.rs && nano ./src/test.rs

Put this code into the file and save it:

pub fn test() {
    println!("Hello from test");
}
  1. nano src/main.rs, replace everything with the lines below, save it:
mod test;

use test::test;

fn main() {
    test();
    println!("Hello, world!");
}
  1. cargo run

Output should be

Hello from test
Hello, world!

Great. We have successfully called another module from main. Now create the lib:

  1. touch ./src/lib.rs && nano ./src/lib.rs Place this code in the file and save it:
pub fn libtest() {
    println!("Hello from lib");
}
  1. cargo run

Output should not change, but you should have a lib and an app in target debug now.

Verify with ls -lall target/debug

Looks good?

OK now:

  1. nano ./src/main.rs Remove all and place this:
mod lib;
mod test;
use test::test;
use lib::libtest;

fn main() {
    libtest();
    test();
    println!("Hello, world!");
}
  1. cargo run

Output is OK, we have called lib and test from main.

Hello from lib
Hello from test
Hello, world!

  1. So now it comes:

nano ./src/lib.rs again and just add mod test; as first line to lib.rs. Nothing else. You want to use test from lib too. That's it. Save and cargo run.

I'm getting this now:

Compiling lib-test v0.1.0 (/Users/decades/Documents/Rust/lib-test)
warning: function is never used: test
--> src/test.rs:1:8
|
1 | pub fn test() {
| ^^^^
|
= note: #[warn(dead_code)] on by default

warning: 1 warning emitted

error[E0583]: file not found for module test
--> src/lib.rs:1:1
|
1 | mod test;
| ^^^^^^^^^
|
= help: to create the module test, create file "src/lib/test.rs"

error: aborting due to previous error

For more information about this error, try rustc --explain E0583.
error: could not compile lib-test.

To learn more, run the command again with --verbose.

The dead code - OK, but why the file not found? I don't get it...

You should not have any mod lib;s in any of your files, Rust automatically detects the presence of lib.rs. Remove the mod lib; from any file it's in.

The mod lib; is confusing the compiler. The error message here could use some work.

src/lib.rs should be:

pub mod test;

pub fn libtest() {
    println!("Hello from lib");
}

and src/main.rs should be:

use lib_test::test::test;
use lib_test::libtest;

fn main() {
    libtest();
    test();
    println!("Hello, world!");
}

By adding a lib.rs file, you're converting your crate into a library. That library crate's name is lib_test. The main.rs is using that library, so it has to have use lib_test::libtest; to use that function.

1 Like

I've ran into this issue before myself. I think the error message here is the worst I've encountered in Rust (following the advice will loop the two error messages into eternity) and overall the way it all works is confusing. Personally I think cargo should just reject mod lib; in main.rs and give an appropriate error message if someone tries to do it.

To expand on my point a bit:

This works

// src/main.rs
mod lib;
fn main {}
// src/lib.rs

This doesn't

// src/main.rs
mod lib;
fn main {}
// src/lib.rs
mod test;
// src/test.rs

The error suggests help: to create the module `test`, create file "src/lib/test.rs". Based on the error message, you may simply try to move test.rs to lib, however...

This doesn't work either

// src/main.rs
mod lib;
fn main {}
// src/lib.rs
mod test;
// src/lib/test.rs

The compiler tells us to create lib/test.rs: help: to create the module `test`, create file "src/test.rs". It doesn't really make sense, but let's try having two test.rs files!

This works again...for some reason. Note the comments!

// src/main.rs
mod lib;
fn main {
    lib::test::lib_test(); // this works
    // lib::test::root_test(); this doesn't
}
// src/lib.rs
pub mod test;
// use test::lib_test; neither of these work, but...
// use test::root_test; this line doesn't actually cause an error if both lines are uncommented
// src/lib/test.rs
pub fn lib_test() {}
// src/test.rs
pub fn root_test() {}

I did find these two open issues:
https://github.com/rust-lang/rust/issues/56314
https://github.com/rust-lang/rust/issues/36146
They haven't seen much activity for a while though.

2 Likes

@ArifRoktim Thanks for the quick reply. I already went to bed with the idea: What, if I need to call test from main now through lib? And here we go with this...Your solution is almost correct. Almost, because if changed like so literally the next error is:

module test is private

~/Documents/Rust/lib-test $ cargo run
Compiling lib-test v0.1.0 (/Users/decades/Documents/Rust/lib-test)
warning: function is never used: test
--> src/test.rs:1:8
|
1 | pub fn test() {
| ^^^^
|
= note: #[warn(dead_code)] on by default

warning: 1 warning emitted

error[E0603]: module test is private
--> src/main.rs:1:15
|
1 | use lib_test::test::test;
| ^^^^ private module
|
note: the module test is defined here
--> /Users/decades/Documents/Rust/lib-test/src/lib.rs:1:1
|
1 | mod test;
| ^^^^^^^^^

error: aborting due to previous error

For more information about this error, try rustc --explain E0603.
error: could not compile lib-test.

To learn more, run the command again with --verbose.

So I changed it to pub mod test; in ./src/lib.rs

However, that little Intellisense like shit in VSCode is still complaining (see snapshot):

but it compiles and works at least.

But I'm still not convinced that this is the proper way to go.

Thanks

@Heliozoa Many thanks for your clear summary. Yes, it pretty much exactly re-describes the problem. Moving the files around gives "Apple's address" in suggestions. Having two of the same files is - hm - suboptimal? And If I get your last comments right, it doesn't even work?

So what is the proper solution of this common problem?

The proper way is to remove mod lib; and use the library with use lib_test::something; like in @ArifRoktim's answer. The remaining IDE issue in your previous post might be caused by having included test.rs twice by having mod test; in both main.rs and lib.rs. If you still have mod test; in main, try removing it and see if that helps.

I tend to agree.

There is still yet another "solution", but this again leaves the "file not found test" IDE warning and an additional "dead code" (for test)" in test.rs.

Decorate the path in lib.rs:

#[path = "./test.rs"]
mod test;

pub fn libtest() {
    println!("Hello from lib");
}

Then you can mod test and mod lib again. But as said: It gives dead code, most likely, because test form test is implicitly called through lib instead out of test directly.

@Heliozoa No, test is not included in main.rs, just in lib.rs. The warning is just in VSCode, not in Cargo.

src/lib.rs

pub mod test;

pub fn libtest() {
    println!("Hello from lib");
} 

src/main.rs

use lib_test::test::test;
use lib_test::libtest;


fn main() {
    libtest();
    test();
    println!("Hello, world!");
}

This is my last version. It compiles and runs. It just gives this red note in VSCode ("file not found", decorated with rustc E0583, as if rustc has been asked for it...)

There is still something what doesn't match the expected layout.

In this case, test.rs is in ./src/test.rs, right? I replicated the project structure and get no errors from VSCode. Are you using the rust-analyzer extension? If yes, as helpful as it is, I find it sometimes trips up and I have to do Ctrl+Shift+P -> Rust Analyzer: Restart server to remove spurious errors. If not, I recommend you uninstall your current Rust extension and replace it with rust-analyzer (matklad.rust-analyzer).

Alternatively you might be using an old version, or maybe using both rust-analyzer and another extension that conflicts with it.

In any case, the code in this post is correct and should not cause errors in cargo or any IDE.

@Heliozoa: Thanks for your passion. No I didn't use Rust Analyzer explicitly, just the Analyzer part contained in Rust for Visual Studio Code (Rust - Visual Studio Marketplace). But I agree: I restarted VSCode and the problem was gone. Thanks.

So yes, I believe now, the outlined solution is the solution. Trying to get some "higher confirmation"

https://github.com/rust-lang/rust/issues/78266

:slight_smile:

I still have a doubt regarding the naming of the use statement.

In the sample above you suggested use lib_test::test; , that worked. I'm not sure, how this prefix was derived: I don't have a module lib_test, nor a file named like so.

I tried to apply an analogy to my project but failed. Same "main.rs" and "lib.rs" in the ./src directory.

My project is named "dragonfly2rust", the name statement in Cargo.toml is "dragonfly2". But neither "use lib_dragonfly2" nor "use libdragonfly2" nor "use dragonfly2" nor use "dragonfly2rust" works. Any pointer?

use dragonfly2rust (without quotes) should work. If it doesn't, well, could you minimize the erroring case to three files - lib.rs, main.rs and Cargo.toml?