rustdependenciesrust-cargoconditional-compilation

How can I conditionally depend on different versions of a dependency via crate features but use it as if it were a single one?


How can I define a crate that depends on different versions of the same crate with features like below?

[features]
serde_1 = ["dep_serde_1"]
serde_1_0_133 = ["dep_serde_1_0_133"]

[dependencies]
dep_serde_1 = { package = "serde", version = "1.0.0", optional = true}
dep_serde_1_0_133 = { package = "serde", version = "1.0.133", optional = true}

My problem is compiler force me to use them like this:

use dep_serde_1::*;

But I would like to use them like this:

use serde::*;

I only enable one of them at time and use cfg(feature = serde_1) in my code.

The motivating problem is, for example, if my models use actix-0.10 and another crate that uses my models use actix-0.12 it will generate compiler error.


Solution

  • I'm not quite sure I understand what you want. If you want the name of the crate to be serde in your use statements, you can rename them back:

    #[cfg(feature = "dep_serde_1")]
    extern crate dep_serde_1 as serde;
    #[cfg(feature = "dep_serde_1_0_133")]
    extern crate dep_serde_1_0_133 as serde;
    
    // Now you can
    use serde::*;
    

    [Edit:] The above takes care of your use of serde, but serde_derive has its own ideas. When you define a struct like

    #[derive(Serialize)]
    struct Asdf { /* … */ }
    

    serde generates code that looks roughly like this:

    const _: () = {
        extern crate serde as _serde;
        #[automatically_derived]
        impl _serde::Serialize for Asdf { /* …
    

    i.e. it ignores the renaming of the serde crate and tries to use the crate by its original name.

    You can override this behavior with the crate container attribute:

    #[derive(Serialize)]
    #[serde(crate = "serde")]
    struct Asdf { /* … */ }
    

    which will make the generated code use the serde from the outer namespace:

    const _: () = {
        use serde as _serde;
        #[automatically_derived]
        impl serde::Serialize for Asdf {
    

    Note, that mutually exclusive features are not a good idea. If you can, it's better to make one the default and the other to override it.

    I'm also not sure your cargo dependencies are actually doing what you want them to. Cargo doesn't allow depending on a crate twice, and if I force dep_serde_1 to =1.0.0 cargo will complain that there is a conflict.