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

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.

Related

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.

Can I have a Cargo workspace with two binaries relying on a library where only one binary enables a feature of the library?

I have a Cargo workspaces project with the structure:
├── src
├── lib
│   └── Cargo.toml
├── tools
│   ├── src/bin/foo.rs
│   └── Cargo.toml
└── Cargo.toml
., lib and tools are my three workspace members. lib has a feature that enables tracing of the execution of a performance-sensitive function. As this feature adds performance overhead, the main binary should not enable it, but the foo binary is a testing tool which uses it.
However, Cargo workspaces take the union of the features of the two binaries, so the main binary ends up including the feature anyway.
How can I fix this?

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

Building submodule binary crates with cargo

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.

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