Reputation: 894
Suppose I have three crates: foo
, bar
, and baz
.
Cargo.toml
:
[workspace]
members = [
"foo",
"bar",
"baz",
]
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
foo/Cargo.toml
:
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[lib]
name = "foo"
crate-type = ["staticlib"]
[dependencies]
bar = { path = "../bar", default-features = false }
foo/src/lib.rs
:
#![no_std]
extern crate bar as _;
use core::alloc::{GlobalAlloc, Layout};
#[global_allocator]
static ALLOCATOR: Allocator = Allocator;
struct Allocator;
unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
todo!()
}
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
todo!()
}
}
bar/Cargo.toml
:
[package]
name = "bar"
version = "0.1.0"
edition = "2018"
[lib]
name = "bar"
[features]
default = ["heap"]
heap = []
bar/src/lib.rs
:
#![no_std]
#![feature(alloc_error_handler)]
use core::alloc::GlobalAlloc;
use core::alloc::Layout;
extern crate alloc;
#[cfg(feature = "heap")]
#[global_allocator]
static ALLOCATOR: Allocator = Allocator;
struct Allocator;
unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
todo!()
}
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
todo!()
}
}
#[panic_handler]
fn panic(_: &core::panic::PanicInfo<'_>) -> ! {
todo!();
}
#[alloc_error_handler]
fn alloc_fail(_: Layout) -> ! {
todo!();
}
baz/Cargo.toml
:
[package]
name = "baz"
version = "0.1.0"
edition = "2018"
[lib]
name = "baz"
crate-type = ["staticlib"]
[dependencies]
bar = { path = "../bar" }
baz/src/lib.rs
:
#![no_std]
extern crate bar as _;
Here, bar
provides the global allocator, and both foo
and baz
depend on bar
. However, foo
doesn't enable bar
's global allocator to use its original allocator, so foo
depends on bar
without the default features.
Running cargo clippy
on each directory (foo/
, bar/
, and baz/
) succeeds. However, running the command on the project root causes an error:
%cargo clippy
Checking bar v0.1.0 (/tmp/tmp.wlBjM4wNFx/bar)
Checking baz v0.1.0 (/tmp/tmp.wlBjM4wNFx/baz)
Checking foo v0.1.0 (/tmp/tmp.wlBjM4wNFx/foo)
error: the `#[global_allocator]` in this crate conflicts with global allocator in: bar
error: could not compile `foo` due to previous error
Actually, there are no global allocator conflicts as foo
uses its original global allocator and disables bar
's one. How to avoid this error?
rustup 1.24.3 (ce5817a94 2021-05-31)
cargo 1.56.0-nightly (b51439fd8 2021-08-09)
rustc 1.56.0-nightly (0035d9dce 2021-08-16)
Upvotes: 5
Views: 2304
Reputation: 894
This is workspace's property. bjorn3 said on Zulip:
If foo, bar and baz are all compiled together, the heap feature will be globally enabled for bar if either foo or baz depends on it. Cargo will take the union of all the features each dependent crate requires and compile dependencies once with these features.
So, bar
is compiled with the heap
feature because baz
requires it, its feature is also enabled when foo
is compiled. Thus, both foo
's and bar
's global allocators are enabled simultaneously, causing the error.
Upvotes: 3