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_existfound (required bycargo-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:
- Would ignoring missing optional dependencies for inactive features be a problem for Cargo?
- I tried to look through existing issues - has something like this been discussed before?
- 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
- Fix interop_cpp Two fake crates (quickcheck and quickcheck_macros) are added in oreder to give satisfy the cargo build inside the guix container. They are needed only to let `cargo build` craete a va... — committed to Fi3/stratum-1 by UnidenifiedUser 3 years ago
- cargo: Do not download platform2 by default Cargo tries to download dependencies even if it's optional. Stub it to stop download the platform2 repository. See also upstream bug: https://github.com/r... — committed to chromeos/adhd by afq984 a year ago
- delete clippy, doc, and test workflows these fail because cargo checks that the openmm dep is available even though it's optional and not enabled. see rust-lang/cargo#4544 — committed to ntBre/openff-toolkit by ntBre 10 months ago
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 buildwith 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)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
.gitignorefor Cargo.lock.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.
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.
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:
Cargo.tomllocally and add those dependencies in, which is not ergonomic on the dev side.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.