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.
Related
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.
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.
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.
I have a binary Rust project which uses the workspaces to manage sub-crates.
Directory structure
/myapp
Cargo.toml
/src
/tests
test.rs
/crates
/printer
Cargo.toml
/src
myapp/Cargo.toml
[package]
name = "myapp"
[workspace]
members = ["crates/printer"]
Inside of test.rs I can compile extern crate myapp; to pull in the parts of the application that are exposed in src/lib.rs. This works as expected.
However, when attempting to compile extern crate printer; it errors that it cannot find it. I've confirmed that the printer package is correctly placed in the top-level Cargo.lock file.
How do I include my sub-crates into the /tests directory at the top level?
There's nothing special about workspaces or even the concept of tests. If you want to use a crate in Rust code, you have to add it as a dependency:
[dependencies]
printer = { path = "crates/printer" }
See also:
How to define test-only dependencies?
I am new to Rust and attempting to build a test project with Cargo. My Cargo.toml looks like:
[package]
name = "rust-play"
version = "0.0.1"
authors = [ "Bradley Wogsland <omitted>" ]
(but the actual TOML file doesn't omit my email). When I cargo build I am getting the following error:
error: failed to parse manifest at /Users/wogsland/Projects/rust-play/Cargo.toml
Caused by:
no targets specified in the manifest
either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present
My main function is in a src/test.rs file. Do I need to specify that in the TOML file? If so, how? I tried adding
target = "src/test.rs"
to no avail.
As the error says:
either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present
So the direct answer is to add a [[bin]] section:
[[bin]]
name = "test"
path = "src/test.rs"
However, it's far more usual to just place the file in the expected location: src/main.rs. You could also place it in src/bin/test.rs if you plan on having multiple binaries.
If it's actually for testing your code, then unit tests go in the same file as the code they are testing and integration tests go in tests/foo.rs.
Alternative issue and solution: You can also be faced with this error if you have copied Cargo.toml file to a parent folder of the crate.
I ran into this issue on Ubuntu 20.04 after having inadvertently copied Cargo.toml to my home folder. Even though my working directory had a properly defined Cargo.toml, the copy in $HOME was taking precedence and causing builds to fail.
In my case and probably in your case as well, the rs file was not named main.rs while Cargo assumes that src/main.rs is the crate root of a binary crate. So, the rule is that If project is an executable, name the main source file src/main.rs. If it is a library, name the main source file src/lib.rs.
Additionally, Cargo will also treat any files located in src/bin/*.rs as executables like mentioned in the previous answer.
As a summary:
If you use cargo new xxx --bin, you will find the file in the src directory is named main.rs. And when you check the file Cargo.toml. It is the same as you written. So the first way is to change the file in src to main.rs
As the cargo report, we can use the [[bin]] to set the file. #Shepmaster has solved it.
Both two ways can work.
I also had this issue and it was because the parent directory also contained a Cargo.toml file and it was prioritising that over the one in the current directory