If a crate is used both as a normal dependency and a build-dependency, features enabled for the build-dependency are also enabled for the normal dependency. This leads to build failures in the no_std world, because an use_std feature that is turned on for the build-dependency is also turned on for the normal dependency.
Minimal example
cargo new bar --lib
cd bar
cargo new foo --lib
In bar/foo/Cargo.toml:
[features]
default = ["use_std"]
use_std = []
In bar/foo/src/lib.rs:
#[cfg_attr(not(feature = "use_std"), no_std)]
pub fn return_42() -> u32 { 42 }
#[cfg(feature = "use_std")]
pub fn print_42() {
println!("{}", return_42());
}
In bar/Cargo.toml:
[dependencies.foo]
path = "foo"
default-features = false
[build-dependencies.foo]
path = "foo"
In bar/src/lib.rs:
#![no_std]
extern crate foo;
pub fn return_42() -> u32 {
foo::return_42()
}
Compiling with cargo build --verbose:
Compiling foo v0.1.0 (file:///…/bar/foo)
Running `rustc --crate-name foo foo/src/lib.rs --crate-type lib --emit=dep-info,link
-C debuginfo=2
--cfg 'feature="default"' --cfg 'feature="use_std"'
-C metadata=5cd2c90dafa7c435 -C extra-filename=-5cd2c90dafa7c435
--out-dir /…/bar/target/debug/deps
-C incremental=/…/bar/target/debug/incremental
-L dependency=/…/bar/target/debug/deps`
Compiling bar v0.1.0 (file:///…/bar)
Running `rustc --crate-name bar src/lib.rs --crate-type lib --emit=dep-info,link
-C debuginfo=2 -C metadata=0a475a34b1347c78
-C extra-filename=-0a475a34b1347c78 --out-dir /…/bar/target/debug/deps
-C incremental=/…/bar/target/debug/incremental
-L dependency=/…/bar/target/debug/deps
--extern foo=/…/bar/target/debug/deps/libfoo-5cd2c90dafa7c435.rlib`
We see that --cfg 'feature="default"' --cfg 'feature="use_std"' is passed, i.e. the use_std feature is activated even though default-features = false is used. When we comment out the [build-dependencies.foo] section, foo is built without the use_std feature.
Breaking no_std libs
The problem is that compilation for custom targets using xargo/cargo-xbuild fails when the std feature is activated for the custom target:
cargo xbuild --target some-custom-target.json --verbose
+ "rustc" "--print" "sysroot"
+ "rustc" "--print" "target-list"
+ RUSTFLAGS="--sysroot /…/bar/target/sysroot"
+ "cargo" "build" "--target" "some-custom-target" "--verbose"
Compiling foo v0.1.0 (file:///…/bar/foo)
Running `rustc --crate-name foo foo/src/lib.rs --crate-type lib --emit=dep-info,link
-C debuginfo=2
--cfg 'feature="default"' --cfg 'feature="use_std"'
-C metadata=beb376bcf23896f4
-C extra-filename=-beb376bcf23896f4
--out-dir /…/bar/target/some-custom-target/debug/deps
--target /…/bar/some-custom-target.json
-C incremental=/…/bar/target/some-custom-target/debug/incremental
-L dependency=/…/bar/target/some-custom-target/debug/deps
-L dependency=/…/bar/target/debug/deps
--sysroot /…/bar/target/sysroot`
error[E0463]: can't find crate for `std` ] 0/2: foo
|
= note: the `some-custom-target-6722811146760112169` target may not be installed
error: aborting due to previous error
For more information about this error, try `rustc --explain E0463`.
error: Could not compile `foo`.
We see that the use_std feature is turned on even though we are compiling for the custom target. So this is definitely not the build dependency getting built because build scripts are compiled for the host target.
Workarounds
There are two ways to work around this, but both have sigificant downsides:
Both workarounds don't really work for build dependencies of dependencies.
Versions
cargo 1.29.0-nightly (af9e40c26 2018-07-05)
release: 1.29.0
commit-hash: af9e40c26b4ea2ebd6f31ee86ee61d5ac1c74eb0
commit-date: 2018-07-05
rustc 1.29.0-nightly (254f8796b 2018-07-13)
binary: rustc
commit-hash: 254f8796b729810846e2b97620032ecaf103db33
commit-date: 2018-07-13
host: x86_64-unknown-linux-gnu
release: 1.29.0-nightly
LLVM version: 7.0
If a crate is used both as a normal dependency and a build-dependency, features enabled for the build-dependency are also enabled for the normal dependency. This leads to build failures in the
no_stdworld, because anuse_stdfeature that is turned on for the build-dependency is also turned on for the normal dependency.Minimal example
In
bar/foo/Cargo.toml:In
bar/foo/src/lib.rs:In
bar/Cargo.toml:In
bar/src/lib.rs:Compiling with
cargo build --verbose:We see that
--cfg 'feature="default"' --cfg 'feature="use_std"'is passed, i.e. theuse_stdfeature is activated even thoughdefault-features = falseis used. When we comment out the[build-dependencies.foo]section,foois built without theuse_stdfeature.Breaking no_std libs
The problem is that compilation for custom targets using
xargo/cargo-xbuildfails when thestdfeature is activated for the custom target:We see that the
use_stdfeature is turned on even though we are compiling for the custom target. So this is definitely not the build dependency getting built because build scripts are compiled for the host target.Workarounds
There are two ways to work around this, but both have sigificant downsides:
no_stdmode and don't use any std-dependent features and build scripts. This makes writing build scripts harder.Both workarounds don't really work for build dependencies of dependencies.
Versions