#how do you side-step circular dependencies not being allowed in cargo?

25 messages · Page 1 of 1 (latest)

elfin grail
#

I have a crate, app_internal that I would like to collect features from other crates in its project, but I would also like the crates that loan their features to app_internal to be able to import from app_internal to retrieve the features loaned to app_internal itself.

E.G: I have a crate, shader_core with plugins I'd like app_internal to import, but I would like shader_core to import other crates(not yet added) in app_internal.

I've tried making it an optional dependency within app_internal, and just set shader_core to not use the shaders feature to not cause a self import, but rust still complains about circular dependencies?

app_internal ```toml
[package]
name = "app_internal"
version = "0.1.0"
edition = "2024"

[dependencies]
shader_core = {path = "../shader_core", optional = true}

[features]
shaders = ["dep:shader_core"]


and

`shader_core`: ```rust
[package]
name = "shader_core"
version = "0.1.0"
edition = "2024"

[dependencies]
app_internal = {path = "../app_internal", default-features = false}

Is there a way to get what Im trying to do to work?

fringe glen
#

No.

#

[dependencies] of this shape will always fail. Features don't help because features just change compilation options — nothing that breaks the cycle.

zealous crescent
#

dependencies always have to be a tree

#

there is no way around that

elfin grail
zealous crescent
#

because compilation is different from building the dependency tree

#

cargo needs to work out the order in which crates can be compiled in

elfin grail
zealous crescent
#

before any compilation can happen to begin with

fringe glen
#

"app_internal with optional dep" and "app_internal without optional dep" are not different crates

#

they are two ways to build the same crate

#

and in any given build, Cargo will pick one or the other, not both

#

(even if it did pick both somehow, you wouldn't achieve a circular dep, you'd just get two distinct copies)

gloomy nexus
elfin grail
gloomy nexus
#

It would have to be one that shader_core can depend on and one that can depend on shader_core

#

Or alternatively shader_core could be

fringe glen
#

note the following big-picture principle: if you have an actual circular dependency between items (e.g. fn foo() calls fn bar() and fn bar() calls foo()), then those items must be in the same crate — or there must be a trait involved, to resolve things later in a single crate

elfin grail
elfin grail
fringe glen
#

I think the most practical way to do this is to store your examples in another package separately from any sub-crate

#

lots of projects do this

#

technically, you can have a "circular" dep via [dev-dependencies] (which the examples get to use) but tools can get confused by this so I wouldn't necessarily recommend it

elfin grail