Creating a library and executable in a single project [duplicate] - rust

This question already has answers here:
Package with both a library and a binary?
(4 answers)
Closed 7 years ago.
How do I create a library and executable in one project? I just want to test my library while working on it and using tests isn't always the best way to do that. I believe I have to use [lib] and [???] but I haven't found the information about that at crates.io.

Indeed, it's strange that crates.io does not have a clear example of this.
To add both a library and an executable to your crate (BTW, the crate can only have one library in it), you need to defined them in [lib] and [[bin]] sections:
[lib]
name = "yourcrate"
[[bin]]
name = "yourcrate_bin_1"
[[bin]]
name = "yourcrate_bin_2"
With the above by default Cargo will look for the library crate root in src/lib.rs and for binaries in src/bin/yourcrate_bin_1.rs and src/bin/yourcrate_bin_2.rs. You can change paths to the crate root files with path option:
[[bin]]
name = "yourcrate_bin_2"
path = "src/yourcrate_bin_2.rs"

Related

How to disable lints for the "bin" target only [duplicate]

This question already has answers here:
How to disable unused code warnings in Rust?
(11 answers)
Closed 3 years ago.
I have a Rust project folder structure that contains an executable and a shared C-compatible library that are both build using the same sources. The Cargo.toml manifest file looks like:
[package]
name = "foo-bar"
version = "0.1.0"
authors = ...
[lib]
name = "foo_bar"
crate-type = ["rlib", "cdylib"]
[[bin]]
name = "foo-bar"
test = false
doc = false
[dependencies]
...
As the executable is not using all of the code I get some "unused code" warnings when building the project with cargo build. I could add #[allow(dead_code)] lints all over my source code where necessary but that would disable them also when building the library target.
Is there a way to globally disable the "dead_code" lint only when compiling the (feature-wise smaller) bin executable target but having it enabled for the lib target?
You can modify a lint for a whole crate by putting an attribute with #! at the beginning of the crate:
main.rs:
#![allow(dead_code)]
// etc.

How to import a crate dependency when the library name is different from the package name?

I have a crate that is imported straight off of GitHub, as per Cargo's documentation:
[dependencies]
libfoo = { git = "ssh://git#github.com/me/libfoo", branch = "dev" }
[lib]
path = "src/rust/lib.rs"
name = "myprj"
crate-type = ["cdylib"]
Running cargo build works fine here, Cargo fetches libfoo and builds it in the ~/.cargo directory. When I try to use (import) it in lib.rs:
extern crate libfoo; //also tried foo
Cargo chokes:
error[E0463]: can't find crate for `libfoo`
--> src/rust/lib.rs:1:1
|
1 | extern crate libfoo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
Interestingly, IntelliJ's Rust plugin does find the crate when I click on it in lib.rs – it navigates to the downloaded source in ~/.cargo...
In the dependency libfoo, the lib section of the Cargo.toml file is specified as:
[package]
name = "libfoo"
[lib]
name = "foo"
crate-type = ["cdylib"]
I have tried all permutations of libfoo and foo to see if Cargo is getting confused between the lib name and the package/directory name.
It also fails if I specify a local path to the dependency. (Cargo compiles the dependency but then claims not to find it when it is declared/imported in lib.rs.)
[dependencies]
libfoo = { path = "/Users/me/dev/libfoo" }
If I include a crate from git or the file system that has the same [lib] name as the [package] name, it works fine. So it appears the problem is with crates that have a have a library ([lib]) name that is different from the package ([package]) name.
If I remove the [lib] section from the dependency's Cargo.toml file, it works.
Update: if crate-type = ["cdylib"] is removed from libfoo, this works with foo imported. If that is there, I get the same error with extern crate foo;.
Cargo is interested in package names when it comes to dependencies, while the compiler (rustc) is interested in library names when it comes to loading their metadata and linking with them.
Let's take a look again at this Cargo.toml excerpt:
[package]
name = "libfoo"
[lib]
name = "foo"
Here, the package name is libfoo and the library name is foo.
When you want to declare a dependency on libfoo in your project, you need to write the package name (libfoo) in the [dependencies] table. For example:
[dependencies]
libfoo = { git = "ssh://git#github.com/me/libfoo", branch = "dev" }
This is what you already have, and it's correct.
However, when you want to import the library in your crate, you need to write the library name in the extern crate item, i.e.
extern crate foo;
How did I figure this out? First, I wrote libfoo in both Cargo.toml and the extern crate item, as you described. When I ran cargo build, I noticed that libfoo was built successfully, indicating that Cargo correctly resolved the dependency. But I also noticed that the compiler couldn't find libfoo, as you experienced.
I then inspected the command line passed to rustc by running cargo build --verbose. This is what I saw (irrelevant parts omitted):
Running `rustc [...] --extern foo=/[path]/target/debug/deps/libfoo-5cf876c5c8ac1bfb.rlib`
The --extern name=path argument tells rustc that the crate named name is located in path. The name here is foo, so we must write extern crate foo; in the code to reference it.

How to link main.rs to lib.rs dynamically?

I have a crate with both src/lib.rs and src/main.rs.
main.rs is just using extern crate programname (which is lib.rs) and uses certain functions from lib.rs and it's submodules.
The documentation on linking says:
Pure-Rust dependencies are statically linked by default so you can use created binaries and libraries without installing Rust everywhere.
How can I change this behavior so a binary created from main.rs will be dynamically linked to library produced by lib.rs?
I've added the following to Cargo.toml
[lib]
path = "src/lib.rs"
crate-type = ["dylib"]
[[bin]]
name = "programname"
path = "src/main.rs"
But it does not compile and gives me errors like:
error: cannot satisfy dependencies so `std` only shows up once
help: having upstream crates all available in one format will likely make this go away
If I add "rlib" to lib section, it compiles, but the binary is not linked against libprogramname.so

Build only `lib` target

I want to build a dynamic link library (dll).
My Cargo.toml currently looks like this:
[package]
name = "sample"
version = "0.1.0"
authors = ["author"]
[lib]
name = "main"
crate-type = ["dylib"]
[dependencies]
I use VS Code with the RustyCode plugin as my IDE on windows.
When I run the build command this builds into a sample.exe and main.dll.
I know I can run cargo build --lib to only build my lib target but I dont have access to this command inside VS Code (afaik).
Is there anyway to specify that I only want to build the lib target in my Cargo.toml file so I can use the VS Code build command which runs cargo build/cargo run?
Cargo builds files using convention over configuration approach. When it finds a main.rs it builds an executable, and when it encounters lib.rs it expects to build a library.
Calling your lib main managed to confuse Cargo. The only solution I managed to find is to either change name of your crate from name = "main" to name = "foo" (and then rename your main.rs into foo.rs) or to change its name to lib.rs, as you did.
Just figured it: Rename the src/main.rs to src/lib.rs and it only builds the lib target!

failed to parse manifest - no targets specified

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

Resources