What is the difference between library crates and normal crates in Rust? - rust

While reading the official book, I stumbled upon packages and crates. To create a new "project", this is what I ran:
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
The book states the following:
A package must contain zero or one library crates, and no more. It can contain as many binary crates as you’d like, but it must contain at least one crate (either library or binary).
My doubt is, what is the difference between binary crates and normal crates?

The difference is between binary crate and library crate. There are no "normal" crates.
A binary crate is an executable program.
A library crate is a library of reusable components that can be included in another library crate or in a binary crate.

Related

rust libraries with cargo (rlib)

I am trying to create a library in rust to be used with rust executables. In C you can just create your .a or .so (or .lib or .dll on windows) and use tools like CMake to link everything, however rust does not seem to have this kind of infrastructure?
It is possible to make an executable with cargo (cargo new ) and create a library by adding the --lib flag (cargo new --lib), but then how would you use the resulting .rlib file (from the library cargo project)? I managed to link the .rlib file as follows:
rustc main.rs --extern foo=libfoo.rlib
and that works beautifully, though, I am not interested in writing a thousand rustc commands to build the final executable (which depends on the .rlib) if there is cargo that can do that for you. I tried working with a build script (which works perfectly for any C library, static or dynamic), but if I try it with the .rlib file, cargo says that it cannot find "foo" (-lfoo), the build script:
fn main() {
println!("cargo:rustc-link-search=.");
println!("cargo:rustc-link-lib=foo");
}
I tried replacing the path (search) to different directories (whilst also moving the .rlib file to the correct directory), also tried different combinations of libfoo, libfoo.rlib, ... (note that for the C libaries, foo is sufficient).
So my question really is: How can you create a rust library for private use, and how do you use it with a rust executable in a proper way, avoiding manual rustc commands? Are there tools that do this? Am I missing something in the build script? Perhaps there exists something like CMake for rust?
I suppose it is possible to just create a C interface over the rust code and compile another C project as that does work with cargo.
I do NOT want to publish the code to crates.io as I want this library strictly for private use.
Cargo does not support using pre-compiled .rlibs. Cargo is designed to compile programs fully from source (not counting native libraries).
How can you create a rust library for private use … I do NOT want to publish the code to crates.io as I want this library strictly for private use.
To use a private library, you write a dependency using a path or git dependency (or use a private package registry, but that's more work to set up).
[dependencies]
my-lib-a = { path = "../my-lib-a/" }
my-lib-b = { git = "https://my-git-host.example/my-lib-b", branch = "stable" }
Your private library is now compiled exactly like a “public” one.

Referencing crate data types and functions from build script

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.

How does cargo manage dependency versions?

I was reading this at the guessing game tutorial inside the rust book
Ensuring Reproducible Builds with the Cargo.lock File
Cargo has a mechanism that ensures you can rebuild the same artifact every time you or anyone else builds your code: Cargo will use only the versions of the dependencies you specified until you indicate otherwise. For example, say that next week version 0.8.4 of the rand crate comes out, and that version contains an important bug fix, but it also contains a regression that will break your code. To handle this, Rust creates the Cargo.lock file the first time you run cargo build, so we now have this in the guessing_game directory.
When you build a project for the first time, Cargo figures out all the versions of the dependencies that fit the criteria and then writes them to the Cargo.lock file. When you build your project in the future, Cargo will see that the Cargo.lock file exists and use the versions specified there rather than doing all the work of figuring out versions again. This lets you have a reproducible build automatically. In other words, your project will remain at 0.8.3 until you explicitly upgrade, thanks to the Cargo.lock file.
but didn't quite understand how cargo garantees that we have/need the correct version of a dependency. For instance, if we put in the [dependecies] rand="0.8.3" it will not exactly download the crate at this version, but the crate the match the needs of our program but it's compatible with this version(?)
Please clarify this logic!
When specifying a crate in Cargo.toml, you can give an exact version (e.g. =0.8.3) or more general indications (e.g. 0.8.*).
If you specify rand = "=0.8.3" in Cargo.toml, then cargo will take version 0.8.3 (note the extra = inside the version requirement). But if you specify rand = "*", then the first time you build your crate it will take the latest version and write this version to Cargo.lock. That way if you rebuild your crate later cargo will reuse the same version even if a new version has been published on crates.io in the meantime.
Note btw that specifying rand = "0.8.3" does not mean "exactly version 0.8.3", but instead means "any version >=0.8.3 and <0.9": link.

How to use ext4 Rust Crate [duplicate]

I'm trying to work with the rust-http library, and I'd like to use it as the basis for a small project.
I have no idea how to use something that I can't install via rustpkg install <remote_url>. In fact, I found out today that rustpkg is now deprecated.
If I git clone the library and run the appropriate make commands to get it built, how do I use it elsewhere? I.e. how do I actually use extern crate http?
Since Rust 1.0, 99% of all users will use Cargo to manage the dependencies of a project. The TL;DR of the documentation is:
Create a project using cargo new
Edit the generated Cargo.toml file to add dependencies:
[dependencies]
old-http = "0.1.0-pre"
Access the crate in your code:
Rust 2021 and 2018
use old_http::SomeType;
Rust 2015
extern crate old_http;
use old_http::SomeType;
Build the project with cargo build
Cargo will take care of managing the versions, building the dependencies when needed, and passing the correct arguments to the compiler to link together all of the dependencies.
Read The Rust Programming Language for further details on getting started with Cargo. Specifying Dependencies in the Cargo book has details about what kinds of dependencies you can add.
Update
For modern Rust, see this answer.
Original answer
You need to pass the -L flag to rustc to add the directory which contains the compiled http library to the search path. Something like rustc -L path-to-cloned-rust-http-repo/build your-source-file.rs should do.
Tutorial reference
Not related to your post, but it is to your title. Also, cargo based.
Best practice:
external crate named foo
use ::foo;
module (which is part of your code/crate) named foo
use crate::foo;
In both the cases, you can use use foo; instead, but it can lead to confusion.
Once you've built it, you can use the normal extern crate http; in your code. The only trick is that you need to pass the appropriate -L flag to rustc to tell it where to find libhttp.
If you have a submodule in your project in the rust-http directory, and if it builds into its root (I don't actually know where make in rust-http deposits the resulting library), then you can build your own project with rustc -L rust-http pkg.rs. With that -L flag, the extern crate http; line in your pkg.rs will be able to find libhttp in the rust-http subfolder.
I ran into a similar issue. I ended up doing this in my Cargo.toml
[dependencies]
shell = { git = "https://github.com/google/rust-shell" }
Then in my main.rs I was able to add this and compile with success. Note that this cargo package is a macro in my case. Often you will not want to have the #[macro_use] before the extern call.
#[macro_use] extern crate shell;

How to compile to both wasm and binary in a Rust crate?

I'm writing the back-end for a web application and would like to reuse some logic for client-side. I want to use wasm to generate a library which Javascript can use. Suppose the logic is in lib.rs. What should I do, so that:
The back-end can import and use the code in lib.rs as normal, also cargo build generates a binary as expected.
Rust generates a wasm library for lib.rs
I tried adding these to my cargo file (by following this: Rust package with both a library and a binary?):
[lib]
crate-type = ["cdylib", "rlib"]
[[bin]]
name = "mybin"
path = "src/main.rs"
But it seems like cargo is building my binary for the browser, so it is missing all the sys crate.
You can ask for only your library to be built using the --lib option.
cargo build --lib --target wasm32-unknown-unknown
So my current approach is to create a separate package for lib.rs and use it as a dependency for the back-end, as outlined in here:
What is an idiomatic way to have shared utility functions for integration tests and benchmarks?
It seems to work well enough.

Resources