Cannot import modules in lib.rs [duplicate] - rust

This question already has answers here:
Rust modules confusion when there is main.rs and lib.rs
(4 answers)
Closed 1 year ago.
I'm creating an application in Rust. The problem is that I cannot import a module inside lib.rs file and I wonder how am I supposed to do that.
My folder structure looks like this:
src/
├─ lib.rs
├─ main.rs
├─ app.rs
Inside main.rs file I use mod lib to use the library's public functions. But inside lib.rs file I would like to get the public methods from app.rs file, but unlike in other files, I cannot because of a compiler error:
file not found for module `app`
help: to create the module `app`, create file "src\lib\app.rs" or "src\lib\app\mod.rs"rustc(E0583)
Strangely enough, when I move the app.rs file to newly created lib/app.rs, the compiler would like to find the file in the previous location, which is src/app.rs, nor src/lib/app.rs. It gives me a headache.
Thank you for your answers.

Do not write mod lib;, with that name in particular. While this is technically valid code, it results in your code being compiled twice, under different configurations:
cargo sees lib.rs, and tells rustc to compile a library with that as the “crate root”.
Under this condition, mod app; looks for a sibling file and succeeds.
cargo sees main.rs, and tells rustc to compile a binary with that as the crate root.
rustc reads main.rs and sees mod lib;, so it compiles lib.rs again as a module inside of the binary.
Then, submodules of modules are expected to be in subdirectories, which is why it's asking for src/lib/app.rs.
If you are intending to define a library crate (which can be depended on by other packages, or your own integration tests and examples separate from main), then instead of mod lib;, just write paths referring to the library: use foo::app::some_fn_in_app_rs;, where foo is whatever name is specified in your Cargo.toml's [package] section, because that's the name of the library. The library is automatically made available to the binary.
On the other hand, if you don't have any need for a library, then you can just declare modules starting from main. In that case, don't name any of the modules lib. Any name that's not lib or main is fine.
In either case, you can always move the code around later if your needs change. The only thing that is problematic is when you name a module one of the filenames that means something specific to Cargo.

Related

How to properly import other files in rust

I'm trying to understand how to properly setup imports, with two goals in mind:
Every script should be compilable using rustc
Building via cargo is supported swell.
With absolute paths it seems to work.
I cannot get it to work with relative paths.
However it seems wrong to use absolute paths.
Whats the correct way to handle imports?
Lets take two examples into account:
1. Example
src
├── main.rs
├── root
│   └── nested.rs
└── root.rs
abs paths
// main.rs:
#[path="root/nested.rs"]
mod nested
#[path="root.rs"]
mod root
// root.rs:
#[path="root/nested.rs"]
mod nested
rel paths
// main.rs:
mod root;
use crate::root::nested;
// root.rs --\> cannot be compiled using `rustc`.
pub mod nested;
2. Example
src
├── main.rs
├── notnested.rs
└── root.rs
abs paths
// main.rs:
#[path="notnested.rs"]
mod notnested
#[path="root.rs"]
mod root
// root.rs:
#[path="notnested.rs"]
mod notnested
rel paths
// main.rs:
mod root
mod notnested
// root.rs --\> cannot be compiled using `rustc`.
use crate::notnested;
I've got a repo here: https://github.com/cadolphs/aoc_2022/tree/main/src
I used Rust for the Advent of Code 2022. In this project, I have the main.rs for the binary. I have individual modules for each day of the challenge.
Some of these modules are single-file modules (day1.rs) and other modules are in directories like day11. Note that the "entry point" to a module in a folder should be called mod.rs for the import to work normally.
This structure should work for what you're trying to do.

Referencing crate data types and functions from build script

I have a rust binary crate (well, it also has a lib.rs file for tests), and am trying to write a build script. This build script needs to generate a JSON file from a static rust object (custom struct crate::datatypes::ErrorMarkup) using serde, which gets imported by the binary crate. I know I could just reference the static object in the binary crate, but the binary crate must import a JSON file that may eventually come from some other source or may be modified between the build and run phases (i.e. the intent is to ship the built file and the JSON file).
How do I reference crate data types and functions from a build script?
Project structure:
- cargo.lock
- cargo.toml
- markup.json (target file)
- build.rs
- src
- main.rs
- lib.rs (exports)
- datatypes.rs
- tests
- verify.rs
I have tried both use pump_log_tool (my crate) and use crate::src and a billion other variations.
I understand this may be an issue due to build dependencies and runtime dependencies. Is there an obviously better way to achieve this goal?
A build script can't depend on the crate it builds
Cargo compiles build.rs into its own crate with its own dependencies. By making your build script depend on the crate it's building, you create a circular dependency that Cargo can't resolve.
Move the needed types to a different crate
The typical solution is to move the items that are (presumably) defined in datatypes.rs to their own, separate crate, which does not require a build script. (This is also a common pattern with procedural macros.) Your new project structure might look like
/
|- Cargo.toml
|- build.rs
|- src/
| |- lib.rs
| \- main.rs
|- pump_log_tool_types/
| |- Cargo.toml
| \- src/lib.rs
Then, in /Cargo.toml, create a workspace section and add the new crate:
[workspace]
# This is a path relative to the workspace root.
members = ["pump_log_tool_types"]
In pump_log_tool/Cargo.toml, add the pump_log_tool_types crate as both a normal dependency and a build dependency:
[dependencies]
pump_log_tool_types = { path = "pump_log_tool_types" }
[build-dependencies]
pump_log_tool_types = { path = "pump_log_tool_types" }
Now when you build pump_log_tool, the pump_log_tool_types crate will be built once and shared between the build script and the crate itself.

How to import functions from `src` for testing? [duplicate]

This question already has answers here:
How to move tests into a separate file for binaries in Rust's Cargo?
(5 answers)
How do I test private methods in Rust?
(2 answers)
How do I access exported functions inside a crate's "tests" directory?
(2 answers)
How to access functions from the main crate when writing integration tests?
(1 answer)
Closed 2 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
I have been trying to understand how to import functions for testing in Rust for hours with no success. I have a project structure that looks like this:
.
├── Cargo.lock
├── Cargo.toml
├── src
│ ├── main.rs
│ └── funcs
│ ├── mod.rs
│ └── hello.rs
└── tests
└── test_hello.rs
src/funcs/mod.rs:
pub mod hello;
src/funcs/hello.rs:
pub fn hello() {
println!("{}", "hello!");
}
src/main.rs:
mod funcs;
fn main() {
funcs::hello::hello(); // this works
}
src/tests/test_hello.rs
mod funcs; // this import does not work!
#[test]
fn add() {
assert_eq!(2 + 2, 4);
}
#[test]
fn hello_test() {
assert_eq!(funcs::hello::hello(), "hello");
}
How can I import public functions in src so that they can be used in my testing dir?
Create a src/lib.rs file to put most of the logic of your package into a library crate and export the funcs module there:
pub mod funcs;
Now use the library (which contains the module) from wherever you like. In your case, from both src/main.rs and tests/test_hello.rs:
use <crate>::funcs;
Replace <crate> with the name of your library crate which is the same as the package name and your root folder.
A Rust crate can contain a program and/or a library. Tests can only access a library, not a program (and only the public parts of the library). In your case you have only a program, so you can't have tests. In order for tests to work, you will need to:
Split you code into a program (in the main.rs file) and a library (in the lib.rs file).
Make sure that any part of the library that you want to use in the program is public.
Make sure that any part of the library that you want to test is also public.
In main.rs and in the tests, write use foo::hello to access the hello function, replacing foo with the name of your library.
If you want to split the code into modules, declare each module with pub mod mod_name in lib.rs, then import them with use foo::mod_name; in main.rs or in the tests.
Rust considers tests as part of a separate crate, so you have to put use your_crate_name::funcs; at the top of your tests, where your_crate_name is the crate name of your main package as defined in Cargo.toml.

Does Rust allow lib/mod.rs in place of lib.rs?

Considering I have lib.rs and main.rs:
is it possible to create a lib/ folder, to hold and separate the subfolders from src/,
and use lib/ + lib.rs or lib/mod.rs to reference the submodules?
Library main file can be placed anywhere and have an arbitrary name, there's a cargo config section for that:
[lib]
path = "src/lib/mod.rs" # by default it is src/lib.rs
However, I would suggest to look at workspaces, it might be a better fit for you.

Rust mod facing the issue error: file not found for module bytes

I have a project which contains three files main.rs,bytes.rs and provider.rs. I have created mod.rs file and I have included both crate bytes.rs and provider.rs as shown below. whenever I am trying to include mod bytes inside the provider.rs, I get the error, please help me to sort out this.
error: file not found for module bytes
---projectA
+ src
-- main.rs
-- mod.rs
-- bytes.rs
-- provider.rs
I have created mod.rs file
That was completely unnecessary:
mod.rs is only for subfolders of the root folder. For the root, there is already a crate root (main.rs or lib.rs) so there is no situation in which this file is useful
and in edition 2018 mod.rs is not necessary for sub-mods to work (though it is still allowed I think)
You should just have mod bytes; mod provider in the crate root (main.rs). Then, provider.rs can either:
use the item from bytes directly e.g. super::bytes::... or crate::bytes::... will resolve to the relevant symbol from the bytes sibling module
use a similar path in order to use "short forms" for symbols e.g. use super::bytes::Foo will let the module refer to Foo without needing the fully qualified path
See https://stackoverflow.com/a/30687811/8182118 for more, as well as a description of edition 2015.

Resources