Unable to resolve dependencies for crate with multi-version dependencies

:incoming_envelope: ontext: we have a grpc service built with tonic 0.11 which uses hyper 0.14, and a http hyper service uses hyper 1.x

crate A

cargo.toml file:

hyper = "1.5"
hyper014 = { package = "hyper", version = "0.14.10", features = ["full"] }

main.rs

# usage of hyper 1.x
use hyper::{body::{Body, Incoming}};

# usage of hyper 0.14
let http_server = hyper014::server::conn::Http::new();

so far it successfully builds and runs for crate A.

=====

crate B

cargo.toml file:

a = { path = "../crate_a", version = "0.0.1" }

now problem is crate B is unable to build taking crate A as dependency, as the compiler says:

  |
6 |     body::{Body, Incoming},
  |                  ^^^^^^^^ no `Incoming` in `body`
  |
  = help: consider importing one of these structs instead:
          std::net::Incoming
          std::os::unix::net::Incoming

   |
76 |         let http_server = hyper014::server::conn::Http::new();
   |                           ^^^^^^^^ use of undeclared crate or module `hyper014`
   |
help: consider importing this struct
   |
1  + use hyper::server::conn::Http;

see that the rust compiler complains unable to distinguish hyper and hyper014.

I notice that you quoted a "main.rs" file for A. "main.rs" cannot be used as a library. I am guessing what you have done is used a #[path] or include!() to include source code from A into B. That is not how using a library as a dependency works, and it explains why your dependencies are not found — because B's Cargo.toml is the one in use by the build that failed.

To fix the problem:

  • Package A should have a lib.rs file instead of a main.rs file. (It is possible to have both, but can be highly confusing, so I recommend avoiding it for now.)
  • Package B should use items from it by use a::..., not by including source code from A.

If you have any trouble with that, please share your project's file and directory listing and the full error output from cargo check (don't trim off the top and bottom, as they contain important information about what cargo and rustc are doing).

1 Like

hi, that's good catch, actually the file is structured below

crate A

server.rs

# usage of hyper 1.x
use hyper::{body::{Body, Incoming}};

struct ServerA;

# usage of hyper 0.14
let http_server = hyper014::server::conn::Http::new();

lib.rs

pub mod server;

in crate B

cargo.toml file:

a = { path = "../crate_a", version = "0.0.1" }

main.rs

use a::server::ServerA;

====

error is

error[E0432]: unresolved import `hyper::body::Incoming`
 --> /Users/jingwxu/.cargo/registry/src/artifactory.12e92b1ea73044b5/a-0.25.16/src/server/server.rs:6:18
  |
6 |     body::{Body, Incoming},
  |                  ^^^^^^^^ no `Incoming` in `body`
  |
  = help: consider importing one of these structs instead:
          std::net::Incoming
          std::os::unix::net::Incoming

error[E0433]: failed to resolve: use of undeclared crate or module `hyper014`
  --> /Users/jingwxu/.cargo/registry/src/artifactory.12e92b1ea73044b5/a-0.25.16/src/server/server.rs:76:27
   |
76 |         let http_server = hyper014::server::conn::Http::new();
   |                           ^^^^^^^^ use of undeclared crate or module `hyper014`
   |
help: consider importing this struct
   |
1  + use hyper::server::conn::Http;
   |
help: if you import `Http`, refer to it directly
   |
76 -         let http_server = hyper014::server::conn::Http::new();
76 +         let http_server = Http::new();
   |

error[E0404]: expected trait, found struct `Body`
   --> /Users/jingwxu/.cargo/registry/src/artifactory.12e92b1ea73044b5/a-0.25.16/src/server/server.rs:126:12
    |
126 |         B: Body + Send + 'static,
    |            ^^^^ not a trait

Some errors have detailed explanations: E0404, E0432, E0433.
For more information about an error, try `rustc --explain E0404`.
error: could not compile `a` (lib) due to 3 previous errors

Look at the source paths in the error — the code that's failing to compile is /Users/jingwxu/.cargo/registry/src/artifactory.12e92b1ea73044b5/a-0.25.16/src/server/server.rs which cannot be the code for your dependency

a = { path = "../crate_a", version = "0.0.1" }

because it's definitely not the path and has the wrong version number to be the same registry dependency.

You should try getting your a and b code working with purely path dependencies before involving a private registry.

update the issue, sorry for the confusion:

  1. crate_a is able to build/publish to private registry
  2. crate_b failed compilation when takes crate_a as dependency from private registry
a = { version = "0.25.12", registry = "internal" }
  1. crate_b succeeded compilation when takes crate_a as dependency from local path
a = { path = "../crate_a", version = "0.25.12" }

I see. I'm afraid I can't help you with problems with private registries — I am not familiar with using them and I know they have quirks.