Search code examples
rustdependenciesrust-cargo

How to handle version requirements of subdependencies based on features of my library?


Say I have a my-lib crate and I depend on sub-lib. The default usage of my library would only require 1.0 of sub-lib. However if a user enables "my_feature" of my crate, I would require 1.4 of sub-lib. How can I represent that in my Cargo.toml?

[package]
name = "my-lib"
version = "0.1.0"
edition = "2021"

[features]
default = []
my_feature = []

# fantasy syntax
[target.'cfg(feature = "my_feature")'.dependencies]
sub-lib = "1.4"

[target.'cfg(not(feature = "my_feature"))'.dependencies]
sub-lib = "1.0"

1.4 should be considered a superset of 1.0 and in most other scenarios and I would just depend on that. However, in my case some versions of sub-lib 1.x have better performance than 1.4 and I don't want to prevent those users from using a more performant version if they don't need "my_feature". I could also just depend on sub-lib 1.0, but then if a user were to enable "my_feature" they would see a compiler error in my library instead of cargo taking care of it if they happened to be using a pre-1.4 version of sub-lib.

Any ideas on how to accomplish this?


Solution

  • It's not pretty, but you could create a third package which depends on version 1.4:

    [package]
    name = "my-lib"
    version = "0.1.0"
    
    [features]
    default = []
    my_feature = ["dep:my-lib-version-shim"]
    
    [dependencies]
    sub-lib = "1.0"
    my-lib-version-shim = { version = "0.1.0", optional = true }
    
    [package]
    name = "my-lib-version-shim"
    version = "0.1.0"
    
    [dependencies]
    sub-lib = "1.4"
    

    Cargo will (always, unconditionally, unavoidably) unify the package minor versions in use, so the presence of my-lib-version-shim in the dependency graph, even if you don’t use it in code, will force the sub-lib dependency to be at least version 1.4.