How to build multi workspace cargo project in rust - rust

I have multi-workspace Cargo project. It has two workspaces, common and server. common is a lib project and server is a bin project.
The location of the project in Github is here.
Below is the project structure.
.
├── Cargo.toml
├── common
│   ├── Cargo.toml
│   └── src
│   └── lib.rs
├── README.md
└── server
├── Cargo.toml
└── src
└── main.rs
4 directories, 6 files
And the file contents of ./Cargo.toml file is
[package]
name = "multi_module_cargo_project"
version = "0.1.0"
authors = ["rajkumar"]
[workspace]
members = ["common", "server"]
[dependencies]
When I run the command cargo build --all:
error: failed to parse manifest at `/home/rajkumar/Coding/Rust/ProgrammingRust/multi_module_cargo_project/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
So I added below in Cargo.toml but still couldn't build the project.
[[bin]]
name = "server/src/main.rs"
How can I build the project. What I'm missing?

You included a [package] section in your main Cargo.toml file. This section indicates that you want to build a main package in addition to the packages in the workspace. However, you don't have any source files for the main package, so Cargo complains.
The solution is to simply omit the [package] section, and only include [workspace]. This configures a virtual workspace – a workspace that is only a container for member packages, but does not build a package itself.
See the main Cargo.toml file of Rocket for a real-world example of a virtual workspace, and Tokio for a real-world example of a workspace with a main package.

Related

Local crate not found when trying to update edition via cargo fix

Context:
I have a local C library called 'libmaths' that then uses Bindgen to create a 'libmaths-sys' crate that is locally stored in the same directory as my project.
Issue:
I want to use some of the features in the 2021 edition of Rust and currently my project is built off 2018. I am trying to update the project by following the instructions at:
https://doc.rust-lang.org/cargo/commands/cargo-fix.html
Run cargo fix --edition. Consider also using the --all-features flag if your project has multiple features. You may also want to run cargo
fix --edition multiple times with different --target flags if your
project has platform-specific code gated by cfg attributes.
Modify Cargo.toml to set the edition field to the new edition.
Run your project tests to verify that everything still works. If new
warnings are issued, you may want to consider running cargo fix again
(without the --edition flag) to apply any suggestions given by the
compiler.
To run cargo fix --edition I am told by the compiler to remove the edition="2018" in cargo toml. Following this I receive a compile error stating that libmaths-sys cannot be found. The code compiles and executes normally in 2018 but not without this edition tag.
I can not find anyone with a similar issue, this is my first stackoverflow question so not sure how best to show my code given its a context of a small project.
Error code
error[E0432]: unresolved import `libmaths_sys`
--> src/main.rs:1:5
|
1 | use libmaths_sys::*; // lib.rs in sys crate
| ^^^^^^^^^^^^ maybe a missing crate `libmaths_sys`?
File Structure and general overview of project
.
├── Cargo.lock
├── Cargo.toml
├── libmaths
│   ├── add.c
│   ├── add.h
│   └── subtract.c
├── libmaths-sys
│   ├── build.rs
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── src
│   │   └── lib.rs
│   └── wrapper.h
├── README.md
└── src
  ├── lib.rs
  └── main.rs
libmaths contains add.c that returns a + b and subtract.c which returns a - b, with a header add.h directing to both .c files
The Rust code generated by bindgen is attached via lib.rs in the libmath-sys crate which links to the OUT DIR which I have omitted from the tree to save 200 lines of file names.
Try updating edition="2018" to edition="2021"; otherwise it defaults to edition="2015" which requires usage of extern crate.
As #Solomon Ucko directed me to, rustup update held the key.
Running rustup update produced:
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: syncing channel updates for '1.48-x86_64-unknown-linux-gnu'
info: checking for self-updates
stable-x86_64-unknown-linux-gnu unchanged - rustc 1.59.0 (9d1b2106e 2022-02-23)
1.48-x86_64-unknown-linux-gnu unchanged - rustc 1.48.0 (7eac88abb 2020-11-16)
info: cleaning up downloads & tmp directories
In the end, rustup was using the old 1.48 version and not the installed 1.59 version.
To switch to the newer vesion I ran:
rustup default stable
I then could follow the instructions from the link in the original question to change the edition.

Why is cargo build cache invalidating?

I have a barebones workspace project:
.
├── build-debug.sh
├── Cargo.lock
├── Cargo.toml
├── common
│   ├── Cargo.toml
│   └── src
│   └── lib.rs
├── rs-test.iml
├── server
│   ├── Cargo.toml
│   └── src
│   └── main.rs
└── wui
├── Cargo.toml
└── src
└── lib.rs
The rs files either empty or just an empty main function.
The server and the wui depends on common: common = { path = "../common" }.
The common project has one crates.io dependency with I suppose build script or proc macro dependency.
The build script:
cargo build -p wui --target wasm32-unknown-unknown
cargo build -p server
The problem:
When I rebuild the unchanged project, some wui dependencies are getting invalidated/rebuilt, then the same for server.
Either:
remove the wasm32 target flag
replace the dependency with a simple crate without build time compiled dependencies
It does not rebuild the subprojects anymore.
Is this a cargo bug? What can I do?
It's probably not a cargo bug. What is likely happening here is that your crates.io dependency (you don't mention what it is, which might have been useful) has different dependencies or features depending on the target architecture. Thus, as you alternate between building the WASM target and your host target, stuff is being rebuilt.
Perhaps it would be better in this case to stop using the Cargo workspace and build the server and wui separately; this way you'll have separate target directories for the server and wui, which takes some extra disk space and takes longer for non-incremental compilation, but will prevent you from having to rebuild that stuff all the time as you build both.

Workspace giving two different behaviors in Rust

I am learning about Cargo workspaces and have set up the following structure:
Top-level:
[package]
name = "workspacer"
version = "0.1.0"
authors = ["ustulation <zzzzzz#gmail.com>"]
[workspace]
members = ["safe_core", "safe_authenticator", "safe_app"]
# If this is removed then each of the sub-projects will have thier own Cargo.lock file
# will build binaries/objects in their own target/ directories. With this present, it's
# always the parent-projects Cargo.lock and target/ directory used. Need to check if this
# is standard behaviour or some bug about to be fixed.
[lib]
crate_type = ["rlib", "cdylib", "staticlib"]
A lib called safe_core which only needs to produce a .rlib
[package]
authors = ["ustulation <zzzzzz#gmail.com>"]
name = "safe_core"
version = "0.1.0"
[dependencies]
maidsafe_utilities = "~0.10.0"
A lib called safe_app which depends on safe_core and needs to produce all 3 .rlib, .a and .so:
[package]
name = "safe_app"
version = "0.1.0"
authors = ["ustulation <zzzzzz#gmail.com>"]
[dependencies]
maidsafe_utilities = "~0.10.0"
safe_core = { path = "../safe_core" }
[lib]
crate_type = ["rlib", "cdylib", "staticlib"]
A lib called safe_authenticator which depends on safe_core and needs to produce all 3 .rlib, .a and .so:
[package]
name = "safe_authenticator"
version = "0.1.0"
authors = ["ustulation <zzzzzz#gmail.com>"]
[dependencies]
safe_core = { path = "../safe_core" }
[lib]
crate_type = ["rlib", "cdylib", "staticlib"]
The tree looks like:
workspacer
├── Cargo.toml
├── safe_app
│   ├── Cargo.toml
│   └── src
│   └── lib.rs
├── safe_authenticator
│   ├── Cargo.toml
│   └── src
│   └── lib.rs
└── safe_core
├── Cargo.toml
└── src
└── lib.rs
If I go to safe_core and build, it creates a target/ folder and Cargo.lock files inside the top level workspacer/, which is good.
If I go to safe_authenticator folder and build that it too uses the same target/ and Cargo.lock files and hence does not recompile safe_core which is what I want too. Same with safe_app.
However if I remove the [lib] section from the top-level workspacer/Cargo.toml, each of the sub-projects start creating their own Cargo.lock files and their own /target directories inside their respective sub-directories. I have mentioned this in the inline comment in the Cargo.toml of workspacer above (the 1st snippet above).
Is this an expected behavior or a bug or am I doing something wrong ?
~$ rustc --version && cargo --version
rustc 1.15.0-nightly (ba872f270 2016-11-17)
cargo 0.15.0-nightly (1877f59 2016-11-16)
After confirming it on latest stable:
~$ rustc --version && cargo --version
rustc 1.13.0 (2c6933acc 2016-11-07)
cargo 0.13.0-nightly (eca9e15 2016-11-01)
It seems to be a bug:
All members of workspace should share the same target directory no
matter what!
A bug report was submitted, and it is solved now.

What is the recommended directory structure for a Rust project?

Where should one put the sources, examples, documentation, unit tests, integration tests, license, benchmarks etc?
Cargo, the official package manager for Rust, defines some conventions regarding the layout of a Rust crate:
.
├── Cargo.lock
├── Cargo.toml
├── benches
│ └── large-input.rs
├── examples
│ └── simple.rs
├── src
│ ├── bin
│ │ └── another_executable.rs
│ ├── lib.rs
│ └── main.rs
└── tests
└── some-integration-tests.rs
Cargo.toml and Cargo.lock are stored in the root of your project.
Source code goes in the src directory.
The default library file is src/lib.rs.
The default executable file is src/main.rs.
Other executables can be placed in src/bin/*.rs.
Integration tests go in the tests directory (unit tests go in each file they're testing).
Example executable files go in the examples directory.
Benchmarks go in the benches directory.
These are explained in more detail in the manifest description.
By following this standard layout, you'll be able to use Cargo's commands to build, run and test your project easily. Run cargo new to set up a new executable project or cargo new --lib to set up a new library project.
Additionally, documentation for libraries is often written in documentation comments (comments that start with /// before any item, or //! to document the parent item). Also, the license is usually put at the root.
Unit tests, as mentioned above, are written in the same module as the functions they're testing. Usually, they're put in an inner module. It looks like this (this is what Cargo generates for a new library with cargo new --lib):
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}

`cargo package`: error: main function not found

I'm trying to package a library using the cargo package manager for Rust. When I try to run cargo package per the documentation, I get the following output:
error: main function not found
error: aborting due to previous error
failed to verify package tarball
I'm confused. I'm trying to package a library (with useful external functions), so I expect that I don't need a main function. Here is my Cargo.toml:
[package]
name = "package-name"
version = "0.0.1"
authors = [ "Kevin Burke <kev#inburke.com>" ]
Here is my directory structure:
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
What am I missing?
Ah! If you are packaging a library for other programs to use (as I am trying to do), you need to name your file lib.rs.
Alternatively, if you are packaging a binary, name your file main.rs (this was my mistake).

Resources