Build errors with workspace


I have a project constructed as "workspace". When make a cargo build from root, there is no build error. But, if I cd in specific one of member, cargo build produce a lot of errors (212). Example :

error[E0277]: the trait bound `Sound: Deserialize<'_>` is not satisfied
    --> battle_core/src/state/client/
10   |     PlayBattleSound(Sound),
     |                     ^^^^^ the trait `Deserialize<'_>` is not implemented for `Sound`
     = help: the following other types implement trait `Deserialize<'de>`:
               &'a Path
               &'a [u8]
               &'a str
               (T0, T1)
               (T0, T1, T2)
               (T0, T1, T2, T3)
               (T0, T1, T2, T3, T4)
             and 141 others
note: required by a bound in `newtype_variant`
    --> /home/bastiensevajol/.cargo/registry/src/
2120 |     fn newtype_variant<T>(self) -> Result<T, Self::Error>
     |        --------------- required by a bound in this associated function
2121 |     where
2122 |         T: Deserialize<'de>,
     |            ^^^^^^^^^^^^^^^^ required by this bound in `VariantAccess::newtype_variant`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `battle_core` (lib) due to 212 previous errors

I don't understand how it's possible (no error when build from workspace root, but errors when build one of member specially). And, the number of errors let me think error are coming from "something else than code itself" (my project build and run correctly).

To reproduce : clone GitHub - buxx/OpenCombat: Open source close combat inspired game, try to build from root (must success), then cd in battle_core folder and build.

Thanks in advance for your time :slight_smile:

Try adding the --workspace flag to cargo build.

According to the Cargo Book:

In a workspace, package-related Cargo commands like cargo build can use the -p / --package or --workspace command-line flags to determine which packages to operate on. If neither of those flags are specified, Cargo will use the package in the current working directory. If the current directory is a virtual workspace, it will apply to all members (as if --workspace were specified on the command-line). See also default-members.

Adding --workspace to the build command, inside the battle_core folder, succeed !

To answer the original question "how is it possible", the most likely cause is feature resolution algorithm (and possibly some other build configuration options). When Cargo builds a project, it unifies features of all its dependencies. This means that you can have the following situation:

-- crate A ---> crate B
-- crate C ---> crate B

Let's assume that B has a feature serde which enables serde impls for its types. Crate A may depend on that serde functionality, and can't be built separately if B/serde is not enabled. But, C also depends on B, and it may have enabled B/serde in its Cargo.toml. Since the features of all dependencies are unified, this implicitly enables B/serde for the dependency of A (since B is built only once, with all required features enabled).

This means that everything will work if you compile A and C together (as when building a workspace), but break if A is compiled separately.

Unfortunately, I don't know of any good way to avoid this kind of error, other than always trying to build the individual crates. Also, I think features are not an only compilation option which can cause such errors, though I don't have an example at hand (possibly sys-crates or crates with complex build scripts can cause some similar issues).


In this case, it seems that battle_core is depending on serde's derive feature

// battle_core/src/audio/
use serde::{Deserialize, Serialize};

#[derive(Debug, Hash, Copy, Serialize, Deserialize, Clone, EnumIter, Eq, PartialEq, Display)]
pub enum Sound {
    // ..

but it does not activate the feature itself

# battle_core/Cargo.toml
serde = "1.0.136"

When building the workspace, the derive feature is activated by at least ggez, depended on by battle_gui.

@bux I noticed you're depending directly on serde_derive and using the derive macros from there. The recommended way is to activate the derive feature and use the macros from serde: Using derive · Serde, this ensures that the crate and the derive macros are always in sync.


Thanks ! That is totally solved the problem :slight_smile: (fix: use correct serde version and derive feature · buxx/OpenCombat@d0f1888 · GitHub)

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.