Building submodule binary crates with cargo - rust

I have the following crate structure:
|── proj/
└── src/
└── bin/
└── foo-bin-rs/
└── src/
└── main.rs
└── Cargo.toml
└── main.rs
└── Cargo.toml
└── build.rs
foo-bin-rs is a submodule. I'd like to find a clean way to issue a build
command through cargo that would build foo-bin-rs as a part of the build
command used for proj. I've not found any documentation that uses the
src/bin directory with binaries that are their own separate crate, just
single files. My first thought was to have a build.rs that issued its own
cargo command, but I couldn't find a flag for cargo that allowed passing a
directory to use as root. What is the canonical solution for this?

My first thought was to have a build.rs that issued its own cargo command, but I couldn't find a flag for cargo that allowed passing a directory to use as root.
There is a command-line argument, but it doesn't expect a directory; rather, it expects a full path to the Cargo.toml file. The argument is named --manifest-path, and it's available on many subcommands, such as build and run. It's used like this (note that relative paths are also valid):
$ cargo build --manifest-path=/path/to/proj/src/bin/foo-bin-rs/Cargo.toml
If you need to run the executable from your build script, you can simply use cargo run to build and run in one go, as usual.

Related

Cargo project with library + multiple binaries, with binaries consisting of multiple files?

The Cargo book describes how to have a library and multiple executable in a single Cargo project.
I'd like to have an executable consist of multiple source files that are specific to that executable and not in the library.
For example
src/lib1.rs, src/lib2.rs, src/lib3.rs in the library itself,
src/bin/exe1.rs + another source file specific to exe1 for the exe1 executable.
Where would I place this last source file so that it's not compiled into the library but compiled into the executable?
The Cargo-supported way to have multiple source files for a single binary in a package is to give it a directory with main.rs. The documentation on “Package Layout” gives this example (I have removed irrelevant elements):
src/
├── lib.rs
└── bin/
├── named-executable.rs
├── another-executable.rs
└── multi-file-executable/
├── main.rs
└── some_module.rs
You want the multi-file-executable case here. Name the directory whatever you want the binary to be named. Your main.rs will then contain mod some_module; in just the same way as if this project had been a simple src/main.rs project.

How do I run cargo flamegraph on unit-tests in lib crate

I have a library crate which I want to profile using cargo flamegraph. But however I try to run cargo flamegraph, I get error messages. The library has the following structure:
utilrs
├── Cargo.lock
├── Cargo.toml
└── src
├── fileprocessor.rs
├── filesplit.rs
├── forwardstar.rs
├── lib.rs
├── persistence.rs
└── xmlparser.rs
What I am looking for is to exectue a test called split_and_process_file within a tests module within the fileprocessor.rs file.
I tried different command line combinations, but they all resulted in errors. Some of the things I tried are:
cargo flamegraph --unit-test -- fileprocessor::tests::split_and_process_file resulting in :Error: crate has no automatically selectable target
and
cargo flamegraph --unit-test utilrs -- fileprocessor::tests::split_and_process_file resulting in error: no bin target named `utilrs`.
System Information:
|Component | Version|
|----------|--------|
|Operating System|Windows 10, 64-bit|
|cargo |cargo 1.65.0-nightly (4ed54cecc 2022-08-27)|
|rustc|rustc 1.65.0-nightly (84f0c3f79 2022-09-03)|
As the error indicates: error: no bin target named 'split_and_process_file', there is no bin target.
A target for cargo is something like lib, bin, etc. That said, there is no such called split_and_process_file function in your main.rs file.
Oops, you don't have main.rs, then you should create one and add your function. Then, run flamegraph with your bin files.. Don't forget to use the --release with cargo run.
As the flamegraph crate page says:
by default, --release profile is used,
but you can override this: cargo flamegraph --dev
If you still want to use a lib but not a bin, then use the --dev thingy.

I want to group executables of rust with attributes as cargo build --release

I've made the following configuration and I can successfully make executables called media and strings. Moreover I want to make executables of media.rs and str.rs. Is it possible to do?
Concretely, I desire executables which are named with media/image, strings/parse so that I can group executables with some attributes.
.
├── Cargo.lock
├── Cargo.toml
└── src
└── bin
├── media
│ ├── image.rs
│ └── main.rs
└── strings
├── main.rs
└── parse.rs
This official document implies that I may can't achieve what I want to do though.
Cargo/Rust does not have a built-in way for you to do this. However, you can use cargo-make. Similar to cargo clippy or cargo fmt, cargo-make is an extension to the cargo command that gives you access to cargo make. It can be installed with cargo install (The --force just tells it to overwrite any previous version of cargo-make).
cargo install --force cargo-make
You can batch together building multiple crates, binaries, or arbitrary shell commands. The main benefit it has over something like a traditional Makefile is it is cross-platform and is optimized so it will build multiple crates at the same time when possible. After installing it with cargo make [task]. Here is an example from their docs of what a Makefile.toml could look like:
[tasks.format]
install_crate = "rustfmt"
command = "cargo"
args = ["fmt", "--", "--emit=files"]
[tasks.clean]
command = "cargo"
args = ["clean"]
[tasks.build]
command = "cargo"
args = ["build"]
dependencies = ["clean"]
[tasks.test]
command = "cargo"
args = ["test"]
dependencies = ["clean"]
[tasks.my-flow]
dependencies = [
"format",
"build",
"test"
]

What's the difference between binary and library in Rust? [duplicate]

This question already has an answer here:
What is the difference between library crates and normal crates in Rust?
(1 answer)
Closed 2 years ago.
What's the difference between binary and library in Rust?
I read The Cargo Book, but couldn't understand it well.
I generated two folders using cargo new a --bin and cargo new b --lib, however, both of them look the same inside. What are the purposes of --bin and --lib? And what are the difference between them?
A binary crate should generate an executable (or multiple) that can be installed in the user's path and can be executed as usual.
The purpose of a library crate on the other hand is not to create executables but rather provide functionality for other crates to depend on and use.
Also they do differ in their structure:
✦2 at [22:50:27] ➜ cargo new --bin somebinary
✦2 at [22:50:29] ➜ cargo new --lib somelib
Created library `somelib` package
✦2 at [22:50:34] ➜ tree somebinary/
somebinary/
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
✦2 at [22:50:41] ➜ tree somelib/
somelib/
├── Cargo.toml
└── src
└── lib.rs
You can also find more information in this rust-lang forum thread: https://users.rust-lang.org/t/what-is-the-difference-between-cargo-new-lib-and-cargo-new-bin/19009
One creates an src/main.rs and other creates src/lib.rs. They are different in the nature of the files which are created. Differences lies in whether you are interested in creating a library or interested in creating a binary
Are you sure you ran those exact same commands?
(ins)temp->tree
.
├── a
│   ├── Cargo.toml
│   └── src
│   └── main.rs
└── b
├── Cargo.toml
└── src
└── lib.rs

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() {
}
}

Resources