How to fix cyclic package dependency?

Hi everyone,

I have an issue with cyclic dependency. My main crate is published on crates.io and it has proc-macro, which is published as separate crate. This proc-macro I also want to use in some my another projects, but the issue is that proc-macro is depends on main crate's traits:

pub struct Imports {
    pub binary_converter: TokenStream2,
    // ...
    pub stream_reader: TokenStream2,
}

impl Imports {
    pub fn get() -> Self {
        Self {
            binary_converter: quote!(crate::traits::BinaryConverter),
            // ...
            stream_reader: quote!(crate::traits::StreamReader),
        }
    }
}

and I want to replace it with:

pub struct Imports {
    pub binary_converter: TokenStream2,
    // ...
    pub stream_reader: TokenStream2,
}

impl Imports {
    pub fn get() -> Self {
        Self {
            binary_converter: quote!(tentacli::traits::BinaryConverter),
            // ...
            stream_reader: quote!(tentacli::traits::StreamReader),
        }
    }
}

For this purpose I set my main crate as a dependency for proc-macro:

[lib]
name = "idewave_packet"
path = "src/lib.rs"
proc-macro = true

[dependencies]
# https://github.com/dtolnay/proc-macro-workshop#debugging-tips
syn = { version = "2.0.49", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"
structmeta = "0.3.0"
tentacli = "8.0.7"

and published next patch version of proc-macro on crates.io. But on build I got this error:

error: cyclic package dependency: package `idewave_packet v1.3.1` depends on itself. Cycle:
package `idewave_packet v1.3.1`
    ... which satisfies dependency `idewave_packet = "^1.3.0"` of package `tentacli v8.0.7`
    ... which satisfies dependency `tentacli = "^8.0.7"` of package `idewave_packet v1.3.1`

Could somebody advice, how can this be fixed ? The only idea I have is to push traits and types into separate crate (and I would like to avoid this, since tentacli already provides all of this).

I believe the answer here is: "tough". You just can't have cyclic crate dependencies.

That said, I'm not sure that having idewave_packet depend on tentacli makes any sense. proc macro crates can't export anything other than proc macros, so it can't re-export the needed parts of tentacli, and just because idewave_packet has a dependency on tentacli in no way means tentacli will be available (or even called that) where the macro is expanded.

You'll probably be better off changing the macro to accept a path as part of its invocation telling it where to look for the traits it needs (i.e. specify either tentacli or crate as part of the invocation).

2 Likes

Indeed, Serde has its crate attribute for this, for example. There are also some crates that make it possible to find the name of a crate by parsing the manifest, but it's likely overkill if it's not a super common case.

The proc macro doesn't need this dependency as it never uses that crate. It only outputs tokens that supposedly refer to it, but may also not as they will be resolved in the context of the caller to your macro.

2 Likes

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.