Overriding dependencies per platform results in conflict

So I have a case where I need to pin a dependency to its exact version on one platform and use a different version of that crate for all others.

This is what I have in my Cargo.toml:

[target.'cfg(not(target_os = "macos"))'.dependencies]
cxx = { version = "^1.0.187", features = ["c++20"] }

[target.'cfg(target_os = "macos")'.dependencies]
cxx = { version = "=1.0.129", features = ["c++20"] }

However cargo update is complaining now:

cargo update cxx
    Updating crates.io index
error: failed to select a version for `cxx`.
    ... required by package `copper-showdown-emulator-sys v0.1.0 (/home/mop/projects/akronyme-analogiker/copper-showdown-editor/crates/copper-showdown-emulator-sys)`
    ... which satisfies path dependency `copper-showdown-emulator-sys` (locked to 0.1.0) of package `copper-showdown v0.3.0 (/home/mop/projects/akronyme-analogiker/copper-showdown-editor/crates/copper-showdown)`
versions that meet the requirements `=1.0.129` are: 1.0.129

all possible versions conflict with previously selected packages.

  previously selected package `cxx v1.0.187`
    ... which satisfies dependency `cxx = "^1.0.187"` of package `copper-showdown-emulator-sys v0.1.0 (/home/mop/projects/akronyme-analogiker/copper-showdown-editor/crates/copper-showdown-emulator-sys)`
    ... which satisfies path dependency `copper-showdown-emulator-sys` (locked to 0.1.0) of package `copper-showdown v0.3.0 (/home/mop/projects/akronyme-analogiker/copper-showdown-editor/crates/copper-showdown)`

failed to select a version for `cxx` which could resolve this conflict

I am puzzled. What am I doing wrong? I thought I can specify mutually exclusive version changes like this :pleading_face:

More background on this for the curious:

With a newer rustc the cxx package generates dozens of warnings inside a macro (not sure if I can somehow allow them - didn't dive into that yet).
Upgrading the cxx package to the latest version worked and I got rid of the warnings.

However I am not using a mac but instead cross compile it for mac in a docker container which has all the mac compiler toolchains onboard (which I need because this is basically a crate that creates a Rust<->C++ bridge). However the new version of cxx adds some static asserts etc that don't work with this toolchain :sob:

So I want to use the latest cxx for normal operations. for the cases I am cross compiling to mac I don't care about the new warnings and want to pin it down to the version I know is compatible with this specific toolchain. It should just work. :sob:

You cannot specify conflicting versions like this because the dependency resolutions stored in Cargo.lock, which are independent of platform, always must specify only one choice of compatible version (you can have both 1.0.129 and 2.0.0, but not both 1.0.129 and 1.0.187).

The simplest option is to allow the warnings:

#![allow(name_of_warning_here)]

cxx::whatever!();

If that does not work or is undesirable, then do this:

  1. Set your dependency requirements to allow both:

    [dependencies]
    cxx = { version = "^1.0.128", features = ["c++20"] }
    
  2. In your cross-compilation container setup, run a command to set the version for that build:

    cargo update cxx --precise 1.0.129
    
  3. Outside of the container, use cargo update normally and you will get the latest cxx.

2 Likes

A related issue for this is Cannot declare different version of dependencies in mutually exclusive targets · Issue #3195 · rust-lang/cargo · GitHub

1 Like