How to stop recompiling an extern crate in Rust - rust

I have a local dependency on some SDK. I make use of
extern crate local_sdk;
use local_sdk::foo;
to use the local_sdk in my implementation.
I am making use of cargo to build. While building, the logs print the following at some stage -
Compiling local_sdk v0.1.0 (file:///project/project-core/sdk/rust)
This happens even though I have already compiled the local_sdk earlier.
How do I prevent recompiling the local_sdk ? It consumes some significant time.
Contents of the my Cargo.toml:
[package]
name = "service"
version = "0.1.0"
authors = ["Rajeev"]
[dependencies]
local_sdk = { path = "../../sdk/rust" }
The local_sdk has the following Cargo.toml:
[package]
name = "local_sdk"
version = "0.1.0"
authors = ["Rajeev"]
[dependencies]
hex = "0.3"
protobuf="2.0"
rand = "0.4.2"
zmq = { git = "https://github.com/erickt/rust-zmq", branch = "release/v0.8" }
uuid = { version = "0.5", features = ["v4"] }
log = "0.3"
libc = "0.2"
ctrlc = { version = "3.0", features = ["termination"] }
[dev-dependencies]
env_logger = "0.3"
[build-dependencies]
cc = "1.0"
glob = "0.2"

Assuming you're using it, there was an issue with RLS that was causing unnecessary rebuilds.
This issue has been fixed, to get the latest version of RLS, use
$ rustup update

Related

unresolved import `serde`/`serde_json`

I build the project without any visible errors but when compiling it I encounter the error E0432 that tells me that serde and serde_json are not found when they have been declared in the Cargo.toml. I tried rebuilding the project from scratch, cargo check and cargo build multiple times and I'm still stuck
The error(s):
error[E0432]: unresolved import `serde`
--> main.rs:1:5
|
1 | use serde::{Deserialize, Serialize};
| ^^^^^ maybe a missing crate `serde`?
error[E0432]: unresolved import `serde_json`
--> main.rs:2:5
|
2 | use serde_json::Result;
| ^^^^^^^^^^ maybe a missing crate `serde_json`?
error: cannot determine resolution for the derive macro `Serialize`
--> main.rs:4:10
|
4 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^
|
= note: import resolution is stuck, try simplifying macro imports
error: cannot determine resolution for the derive macro `Deserialize`
--> main.rs:4:21
|
4 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^
|
= note: import resolution is stuck, try simplifying macro imports
error[E0433]: failed to resolve: use of undeclared crate or module `serde_json`
--> main.rs:14:32
|
14 | let config: ConfigStruct = serde_json::from_str(&config_data).unwrap();
| ^^^^^^^^^^ use of undeclared crate or module `serde_json`
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0432, E0433.
For more information about an error, try `rustc --explain E0432`.
main.rs file:
use serde::{Deserialize, Serialize};
use serde_json::Result;
#[derive(Serialize, Deserialize)]
struct ConfigStruct {
playlist_name: String,
replace_cover: bool,
delete_songs: bool,
songs_ids: Vec<String>,
}
fn get_config() -> Result<ConfigStruct> {
let config_data = std::fs::read_to_string("../config.json").unwrap();
let config: ConfigStruct = serde_json::from_str(&config_data).unwrap();
Ok(config)
}
fn main() {
let config = get_config().unwrap();
println!("{}", config.playlist_name);
}
Cargo.toml file:
[package]
name = "grrs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = {version = "1.0.144", features = ["derive"] }
serde_json = "1.0.85"
Cargo.lock file:
# This file is automatically #generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "grrs"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "itoa"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
[[package]]
name = "proc-macro2"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "serde"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
You need to enable derive feature from serde crate.
Your cargo.toml file should look something like this:
[package]
name = "grrs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0.144", features = ["derive"] }
serde_json = "1.0.85"
rspotify = "0.11.5"
Notice the feature key in the serde dependency decleration.

How to publish a crate with optional dependency?

I have some trouble about publishing crates with optional dependencies.
First, I execute cargo publish, but I don't see any optional dependencies compiled.
Then, I run cargo publish --all-features. The dependencies were compiled, but I don't see any modules with optional dependency in the documentation generated by crates.io.
What is the correct way to publish a crate with an optional dependency, which does not a default feature setting in Cargo.toml?
cargo publish is the correct way to do it.
If you want that docs.rs (not crates.io) builds your documentation with some features enabled, use the package.metadata.docs.rs section in your Cargo.toml. I use the Cargo.toml from the petgraph crate as an example (stripped):
[package]
name = "petgraph"
version = "0.6.0"
description = "Graph data structure library. Provides graph types and graph algorithms."
edition = "2018"
[dependencies]
fixedbitset = { version = "0.4.0", default-features = false }
indexmap = { version = "1.6.2" }
quickcheck = { optional = true, version = "0.8", default-features = false }
serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true }
[...]
[features]
default = ["graphmap", "stable_graph", "matrix_graph"]
graphmap = []
stable_graph = []
matrix_graph = []
serde-1 = ["serde", "serde_derive"]
[package.metadata.docs.rs]
features = ["serde-1", "quickcheck"]

How to include dependency based on optional dependency?

In Rust Cargo, how can I include optional features of dependencies, depending on the inclusion of another dependency?
Specifically, I would like to offer a "serde" feature, which enables serde support. What I can do is [1]
[dependencies]
serde = { version = "1.0", optional = true }
Rust exports this dependency as a feature automatically (as I understand it).
However, I use other dependencies, which offer a "serde" feature, too:
[dependencies]
otherpackage = { version = "1.0", features = ["serde"] }
serde = { version = "1.0", optional = true }
Now, the serde feature of "otherpackage" should only be included if the "serde" feature is activated for this package. But cargo does not let me do
[features]
serde = [ "serde", "otherpackage/serde" ]
[dependencies]
otherpackage = { version = "1.0" }
serde = { version = "1.0", optional = true }
I understand this is due to a name clash between the "serde" feature and the "serde" dependency, which I think is also exported as a feature. So, in essence there are now two "serde" features, which obviously does not work.
How can I solve this with still offering a "serde" feature and without renaming the "serde" package? Ideally, I would just like to disable the automatic exporting of the serde dependency as a feature or be able to specify a feature dependency of the "serde" package.
How can I solve this with still offering a "serde" feature and without renaming the "serde" package?
Since Rust 1.60, “namespaced features” allow this, as documented in the Cargo documentation on optional dependencies. When referring to a crate from within your [features] table, prefix it with dep:, like this:
[features]
serde = [ "dep:serde", "otherpackage/serde" ]
[dependencies]
otherpackage = { version = "1.0" }
serde = { version = "1.0", optional = true }
As soon as you use dep: for an optional dependency, it is no longer treated as implicitly creating a feature, so this also allows giving an entirely different name to the feature than to any dependencies it enables.
The following solution is obsolete and included for historical reference.
Prior to namespaced features, this had to be done by renaming the “serde” dependency. However, this doesn't need to disrupt anything else; as described in “Advanced Cargo [features] Usage”, you can rename it and rename it back. Set up your Cargo.toml like this:
[features]
serde = [ "serde_cr", "otherpackage/serde" ]
[dependencies]
otherpackage = { version = "1.0" }
serde_cr = { package = "serde", version = "1.0", optional = true }
This will make the crate name serde_cr visible to your code. Then rename it back using an explicit extern crate in your lib.rs:
extern crate serde_cr as serde;
However, this has the disadvantage of causing your package to have a feature named serde_cr.

Can cargo.toml contain custom properties

I've recently started with Rust and coming from a Node background I'm curious if the cargo.toml file for a project can be extended to include custom properties.
For example, in Node, some packages let you put configuration options in the package.json file (like babel):
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": [ ... ],
"plugins": [ ... ],
}
}
I've looked through the manifest docs but I can't seem to find anything about custom properties.
For example, what if I had a CLI tool and it has a configurable option. Do I have to have the user make a config file just for this option or could I include in the cargo.toml like so:
[package]
name = "my_project"
version = "0.1.0"
edition = "2018"
# custom property
store: ["one", "two", "three"]
[dependencies]
Also, if this is a "sure, as long as you have name and version as required", is it something that should be avoided?
The Rust equivalent would be Cargo features. You can define features for a crate like this in the crate's Cargo.toml:
[package]
name = "crate_with_features"
version = "1.0.0"
edition = "2018"
[features]
# default set of features
default = ["has_foo", "has_bar"]
# can use these for conditional compilation
has_foo = []
has_bar = []
And then if you had a lib.rs like this:
[cfg(feature = "has_foo")]
pub fn foo() {
println!("foo");
}
[cfg(feature = "has_bar")]
pub fn bar() {
println!("bar");
}
People would be able to select just which features of your crate they want. For example:
[package]
name = "other_project"
[dependencies]
crate_with_features = "1.0.0"
In the default case, crate_with_features would come with both foo and bar functions since the default feature requires both of them, but people could choose to only use one or the other by specifying:
[package]
name = "other_project"
[dependencies.crate_with_features]
version = "1.0.0"
# don't include default feature set
default-features = false
# cherry pick individual features
features = ["has_foo"]
In the above example crate_with_features would only be compiled with the foo function for that project.
The Rust Reference has a page on conditional compilation if you'd like to learn more about that specifically.

Can you test if the feature of a dependency is set using the `cfg!` macro?

I am trying to test if a feature of one of my dependencies has been set using the cfg! macro.
Below is an example:
my-lib/Cargo.toml
[package]
name = "my-lib"
version = "0.1.0"
edition = "2018"
[features]
some-feature = []
my-lib/lib.rs
pub fn some_function() {
if cfg!(feature = "some-feature") {
println!("SET");
} else {
println!("NOT SET");
}
}
my-bin/Cargo.toml
[package]
name = "my-bin"
version = "0.1.0"
edition = "2018"
[dependencies]
my-lib = { path = "../my-lib" }
my-bin/main.rs
use my_lib;
fn main() {
my_lib::some_function();
if cfg!(feature = "my-lib/some-feature") {
println!("is SET in bin");
} else {
println!("is NOT SET in bin");
}
}
Below shows the output given different run conditions. I would expect the second scenario to show is SET in bin.
> cargo run --features ""
NOT SET
is NOT SET in bin
> cargo run --features "my-lib/some-feature"
SET
is NOT SET in bin
A workaround is to add bin-some-feature = ["my-lib/some-feature"] to "my-bin/Cargo.toml" and change the check in "my-bin/main.rs" to cfg!(feature = "bin-some-feature"). This produces the desired output.
> cargo run --features "bin-some-feature"
SET
is SET in bin

Resources