cargo: Cargo fails to run when an *optional* dependency is missing

#!/usr/bin/env bash

set -e

cd /tmp
[ -d cargo-optional-deps ] && rm -rf cargo-optional-deps
cargo new cargo-optional-deps
cd cargo-optional-deps

cargo build
cat >> Cargo.toml <<EOF
optional_dep_does_not_exist = { version = "1.0", optional = true }
EOF
cargo build

Fails with

error: no matching package named optional_dep_does_not_exist found (required by cargo-optional-deps)

I did not expect this because the dependency is not required as per http://doc.crates.io/manifest.html#the-features-section:

optional dependencies, which enhance a package, but are not required; and

I’m running into this behavior while integrating Cargo into a private build system that wants control over dependencies. As such, I need to elide optional dependencies by default in this system’s dependency list.

I’m opening this issue to get some input on:

  1. Would ignoring missing optional dependencies for inactive features be a problem for Cargo?
  2. I tried to look through existing issues - has something like this been discussed before?
  3. An idea about resourcing/priority of the feature and how it fits into the roadmap for Cargo’s integration with existing systems.

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 10
  • Comments: 23 (13 by maintainers)

Commits related to this issue

Most upvoted comments

I’d like to add another “me too” case. I’m working on packaging crates in Fedora. We cannot use crates.io directly, and all crates that are needed during the package build process must be packaged as RPMs. Not all crates are packaged (for various reasons, sometimes lack of resources, sometimes we don’t want to package something), and we want to use cargo build with some optional features disabled and without those crates installed. This is very close to the situation described in the original report for this bug, except that this is a public distro so everything is in the open.

Right now the only workable solution seems to be to edit Cargo.toml files to remove the optional dependencies we don’t want to enable, but that is a terrible hack and makes it much harder to automate the whole process.

Has a decision been made for this issue? I have encountered a case where it is really needed. In fact, one of my dependencies is optional, and needs a crate that is generated locally. I want to be able to build my project without this dependency when its feature isn’t used, and get a compile error if I try to build with this feature and the generated code is missing.

Is there no possible workaround for now?

@cramertj heh I’ve thought we’d hit a problem like this at some point.

A random solution which may help solve this though is to perhaps list the valid targets for a project in a workspace root Cargo.toml. That way Cargo could be smarter and just vendor dependencies for those targets (and alter resolution so it won’t include winapi in the lock file)

So the reason that Cargo needs optional dependencies is that when generating a lock file

I think you’ve hit the nail on the head here. I’m not sure “lock files” are necessary in our system which has its ways of ensuring reproducible builds. Our package template for Rust projects has a .gitignore for Cargo.lock.

but rather you won’t be directly downloading from crates.io

Yup, exactly. Sorry for the ambiguity. We have an “import” process to pull an external dependency into our build system. That process is aware of crates.io.

One thought I had when writing this is that maybe some “shim crates” could work for now?

I’m open to the idea but also skeptical. Right now I don’t care about 32 bit, Windows, etc. There are trees of dependencies I don’t need to worry about if I just remove them. That works great because I can just scrub them from the Cargo.toml and nothing breaks. Optionals are harder because enabling the feature becomes impossible without “unscrubbing” the manifest on demand.

In that sense it may be best to follow the “build system integration” threads and features to see how we can better accommodate your build system

Yeah, I am (trying to). If something in particular is worth investigation, I’d appreciate if you could ping me.

We hit the same issue with an mix of open source and private optional dependencies. We have a public crate A that has an optional dependencies on a private crate B (behind a feature). Cargo is failing to resolve the private crate for anyone who uses A even though it’s behind a feature flag that not enabled.

We also hit this just now.

We have a few internal crates (as path dependencies) that we’d like to optionally enable when a local dev feature is enabled, but we want those crates to never be required in any capacity by our public users.

We now have to either:

  • patch Cargo.toml locally and add those dependencies in, which is not ergonomic on the dev side.
  • add dummy crates and require the users to work form a workspace with those in, which is also very very ugly

I believe this is a very common use case that I’ve seen and used in most of the projects I’ve worked on in my career so far.

I am also open to any horrible hacks and/or suggestions on how to work around this 😅

I’ve just hit the exact same situation as @siscia, where I have an open source project with an optional proprietary component that adds a few extra features. I’m currently working around it by checking in an empty package to the open source project, and then instructing users to overwrite that with the proprietary code if they need it, but this is pretty bad ergonomically.

Has any further thought been given to what a solution here might look like? I’d be happy to help with implementation if there’s a decision about what should be done. Currently, we’re checking in a huge number of vendored crates into the fuchsia tree because they’re pulled in as optional dependencies of something or other, and I’d like to make it possible to omit them.