Linking against binary crate - rust

There's a crate I want to use as a library for some of my own code (speedtest-rs specifically, but it doesn't really matter). However, whenever I try to use this crate, the compiler doesn't want to play nice with it.
$ cargo build
Compiling my-project v0.1.0 (/home/nick/Documents/code/my-project)
error[E0432]: unresolved import `speedtest_rs`
--> src/main.rs:1:5
|
1 | use speedtest_rs::*;
| ^^^^^^^^^^^^ use of undeclared type or module `speedtest_rs`
Looking at the Rust book, it seems like there's a distinction between a binary and library crae
The rand crate is a library crate which contains code intended to be used in other programs
Some googling has shown me that binary crates just have an extra link step, so I should be able to link against them, right? I know a lot of Rust packages have both a library and a binary in them, but what do you do when an author does not seem to follow this pattern?

Some googling has shown me that binary crates just have an extra link step, so I should be able to link against them, right?
No. It's not that simple. Plus that extra step creates an executable file rather than a library file. An executable cannot be used as a library.
I know a lot of Rust packages have both a library and a binary in them, but what do you do when an author does not seem to follow this pattern?
You can:
Ask them on GitHub to publish a library.
Fork the crate and make your own library (which you can do since it is published with the usual dual “Apache License, Version 2.0” + “MIT” license).
There isn't an automated way to use a binary crate as a library because in particular:
Rust won't generate a library.
Since the crate is missing a src/lib.rs file, nothing is exported. This is akin to have all items in that crate private. You wouldn't be able to use anything.

Related

Kebab-case rust modules

I like naming my folders and files by the kebab-case convention.
Recently, I've been learning rust and learned a bit about modules. In one of the examples, I have a file named: distinct-powers.rs. Whenever I do mod distinct-powers to put the code in scope, I obviously get a syntax error since Rust cannot handle kebab-case. The error is: Syntax Error: expected BANGrust-analyzer which I don't think is informing us of anything since it thinks the error is completely different.
Is there any way to circumvent this limitation of Rust?
If you really want to, you can place modules’ code at arbitrary filenames:
#[path = "distinct-powers.rs"]
mod distinct_powers;
But please don’t — one of the great things about Rust is that there is a single standard for project layout, which makes it easy to dive into other people’s code. Every customization is a disruption to someone finding the code they’re looking for.
There are a couple of locations where hyphens are allowed, that is, a kebab-case name can be used in a Rust package. They all have to do with Cargo, the build system, rather than the Rust language itself.
The name of the package itself (as specified in Cargo.toml) can be kebab-case. If the package is a library, Cargo will automatically translate this to snake_case for the library's crate name (which is how you refer to it within Rust code in dependents). This is quite commonly done.
For example, in this docs URL, https://docs.rs/ordered-float/latest/ordered_float/, you can see that the package name is ordered-float and the crate name (which could be overridden but was not) is derived from that as ordered_float.
The name of a binary, example, or test target can contain hyphens. This means that the binaries built in target/ can have kebab-case names — cargo run --bin distinct-powers is valid.
These names can all be used by Cargo target auto-discovery and thus are not considered non-standard layout.
kebab-enthusiast/
Cargo.toml
src/
lib.rs
snake_module.rs
bin/
kebab-binary.rs
examples/
kebab-example.rs
tests/
kebab-test.rs

Cannot find [package] in the crate root

How do you get rust to recognize a module within a crate? I believed it was enough to declare mod [module name] in lib.rs. Is it not?
Error:
error[E0432]: unresolved import `crate::a`
--> src/bin/b.rs:2:12
|
2 | use crate::a::f;
| ^ could not find `a` in the crate root
src/a.rs:
pub fn f() {}
src/bin/b.rs:
use crate::a::f;
fn main() {}
src/lib.rs:
mod a;
Cargo.toml:
[package]
name = "m"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "b"
path = "src/bin/b.rs"
[dependencies]
You are confusing crates and packages. As per the corresponding chapter in the book:
A crate is the smallest amount of code that the Rust compiler considers at a time. [...] A crate can come in one of two forms: a binary crate or a library crate.
This means that your lib.rs and bin/b.rs files define two separate crates and thus crate refers to different things. Both belong to the same package which is defined by your Cargo.toml file. To use functions from your library crate in your binary crate, use the crate name instead of crate. In your case, the crate name is the same as the package name, which is m. Note that you will have to mark your library items as pub to use them in another crate.
An example of this can be found in the bat program, which uses both crate and bat in the imports of the bat binary crate:
https://github.com/sharkdp/bat/blob/2dbc88d3afdacf6449f299c70f29e5456904779b/src/bin/bat/main.rs
When a binary is compiled it is seen as the root of the project structure. So lib.rs is not compiled for binary targets and you can not use any of its modules unless you also add them in your binary. The most common approach is to put your binaries in the src folder with lib.rs so you don't need to worry about the folder structure when using your modules. I suppose you could use include!("lib.rs"); at the top of your binary to make it inherit everything from your library, but I have not tried it and it would likely be considered bad form.
However, you can sidestep the issue by making your binary depend on your library. The easiest way to do this is by making your binary its own crate which depends on your library.
There are also some ways to get around this, is by making a crate a dependency of itself, but these solutions always make me feel a little uneasy about the stability of the solution. This answer can give you a general idea of what that looks like.
Here are some examples various solutions. In case you are wondering, these are just the first crates I found that fit the design pattern. I do not know what some of them do/contain.
https://github.com/stanislav-tkach/os_info (Workspace members)
https://github.com/sagiegurari/cargo-make (Binaires in source)
https://github.com/hominee/dyer (Subcrates (dyer-macros))
https://github.com/clap-rs/clap (Example binaries)

How to compile all code including dependencies to LLVM IR?

I have a Rust crate A that depends on another Rust crate B; both of them are STD-clean (i.e. both use #![no_std]) and there are no other dependencies. I would like to get my hands on the LLVM IR of all the code needed to statically link it together with lld.
To get the LLVM IR from just A, I am currently passing --emit=llvm-ir to cargo rustc. This results in target/debug/deps/A-someKindOfHash.ll which I can then consume -- in my case, by using Clang to link it with some C code that calls (non-mangled) Rust functions.
However, that .ll file doesn't contain all transitive dependencies, so as soon as A actually starts using functions from B, this breaks down.
How do I tell Cargo to create LLVM IR from all dependencies and put them somewhere under target/?

Why do proc-macros have to be defined in proc-macro crate?

I was trying to create a derive macro for my trait, to simplify some stuff.
I've encountered some problems:
the #[proc_macro_derive] attribute is only usable with crates of the proc-macro crate type
and, after the small fix proc-macro=true:
proc-macro crate types cannot export any items other than functions tagged with #[proc_macro_derive] currently
functions tagged with #[proc_macro_derive] must currently reside in the root of the crate`
What is the reason for this behavior?
Procedural macros are fundamentally different from normal dependencies in your code. A normal library is just linked into your code, but a procedural macro is actually a compiler plugin.
Consider the case of cross-compiling: you are working on a Linux machine, but building a WASM project.
A normal crate will be cross-compiled, generate WASM code and linked with the rest of the crates.
A proc-macro crate must be compiled natively, in this case to Linux code, linked with the current compiler runtime (stable, beta, nightly) and be loaded by the compiler itself when compiling the crates where it is actually used. It will not be linked to the rest of the crates (different architecture!).
And since the compilation flow is different, the crate type must also be different, that is why the proc_macro=true is needed.
About this restriction:
proc-macro crate types cannot export any items other than functions tagged with #[proc_macro_derive]
Well, since the proc-macro crate is loaded by the compiler, not linked to the rest of your crates, any non-proc-macro code you export from this crate would be useless.
Note that the error message is inexact, as you can also export functions tagget with #[proc_macro].
And about this other restriction:
functions tagged with #[proc_macro_derive] must currently reside in the root of the crate
Adding proc_macro or proc_macro_derive items in nested modules is not currently supported, and does not seem to be particularly useful, IMHO.

What's the difference between the "serialize" and "rustc-serialize" crates?

This is the serialize crate, and this is the rustc-serialize crate.
I'm getting deprecation warnings from the compiler when using the Encodable and Decodable traits from the serialize crate. The compiler tells me to use RustcEncodable and RustcDecodable from the rustc-serialize crate.
It seems like this just makes things less readable for the same functionality (apart from base64 encoding provided in rustc-serialize). What's the difference between these crates?
The serialize crate is an internal part of the standard Rust distribution. It won't be available in the Rust 1.0 stable/beta channels.
The rustc-serialize crate used to be serialize, but it was moved out to a separate repository and uploaded to crates.io so that it can evolve on its own.
This was done because the utility of rustc-serialize is enormous but it was not realistic to get it stabilized in time for Rust 1.0. Since the Rust distribution will prohibit unstable features on the stable channel, the only way to continue using the serialization infrastructure is to 1) stabilize what we have or 2) move it to crates.io, where the unstable restrictions don't apply.
rustc-serialize has a lot of known downsides, and it is being worked on, so stabilizing what was there really isn't an option.
But the Decodable/Encodable features require compiler support (because compiler plugins won't be stable either for Rust 1.0). As a stopgap measure, RustcDecodable/RustcEncodable were invented as a temporary measure for the rustc-serialize crate to use explicitly. It's a bit weird, but it leaves the Decodable/Encodable names available for a future backwards-compatible version of a serialize crate that is better than what we have now (perhaps this is what serde2 will become from the aforementioned link).
So for the time being, stick to use rustc-serialize and RustcDecodable/RustcEncodable.
(I apologize that I can't come up with a link to cite all of this. It's knowledge I've accrued over time from GitHub issues. Maybe there is an RFC that lays all of this out though. I can't remember.)
To expand on BurntSushi5's answer, as of the time of this writing, the Rust compiler in both Stable and Beta channels throws the following error when attempting to use vanilla serialize:
error: use of unstable library feature 'rustc_private': deprecated in favor of rustc-serialize on crates.io (see issue #27812)
--> src/main.rs:2:1
|
2 | extern crate serialize;
| ^^^^^^^^^^^^^^^^^^^^^^^
The linked Github issue is not very helpful. In short, use rustc-serialize.

Resources