Description
Problem
Lets say I have two crates, with these contents of Cargo.toml
. The Rust code does not matter here.
# foo/Cargo.toml
[dependencies]
serde = {version = "1.0.133", optional = true, default-features = false}
time = {version = "=0.3.10", optional = true, default-features = false}
chrono = {version = "=0.4.18", optional = true, default-features = false}
[features]
serialization = ["dep:serde", "time?/serde-well-known"]
# bar/Cargo.toml
[dependencies]
foo.features = ["serialization"]
foo.path = "../foo"
# time = "=0.3.11"
# chrono = "=0.4.19"
As you can see, bar
depends on foo
and enables the serialization
feature, but it does not enable the time
nor the chrono
feature.
This results in the following bar/Cargo.lock
file:
bar/Cargo.lock
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "app"
version = "0.1.0"
dependencies = [
"foo",
]
[[package]]
name = "foo"
version = "0.1.0"
dependencies = [
"serde",
"time",
]
[[package]]
name = "itoa"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "num_threads"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
dependencies = [
"libc",
]
[[package]]
name = "serde"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
[[package]]
name = "time"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82501a4c1c0330d640a6e176a3d6a204f5ec5237aca029029d21864a902e27b0"
dependencies = [
"itoa",
"libc",
"num_threads",
"serde",
]
The relevant snippet is at the end:
[[package]]
name = "time"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82501a4c1c0330d640a6e176a3d6a204f5ec5237aca029029d21864a902e27b0"
dependencies = [
"itoa",
"libc",
"num_threads",
"serde",
]
Here the dependency time
is declared, even though it is an optional dependency and nothing enabled the corresponding feature on foo
. The time
dependency even has serde
listed as one of its dependencies too.
I think this is problematic in a couple of ways.
It bloats the Cargo.lock
and makes it imply that changes are larger than they actually are. In the above example adding foo
will also add time
even if that is not necessary.
Dependency management tools will get confused by this. I mean tools like dependabot or cargo audit
, which use the Cargo.lock
as source of truth. Since these tools will see an entry for time
, even if it is unused, they will create pull requests or warn about security vulnerabilities which do not exists.
This prevents using two crates with conflicting version requirements. You can see what happens if you uncomment the lines in bar/Cargo.toml
.
Uncommenting time
will fail, since now two conflicting version constraints (=0.3.10
!= =0.3.11
) exist.
However, uncommenting chrono
works with the conflicting versions (=0.4.18
!= =0.4.19
).
Steps
- Create project
foo
with the above content forCargo.toml
. - Create project
bar
with the above content forCargo.toml
. - Observe how the
Cargo.lock
ofbar
contains an entry fortime
and even a transitiveserde
dependency intime
.
Possible Solution(s)
Disabled optional dependencies should not be tracked in Cargo.lock
, even if there is a weak dependency linking to it. This brings it in line with "normal" optional dependencies.
Notes
While the time
entry exists in the Cargo.lock
, it appears cargo correctly ignores it when building the code. There is neither a Compiling time ...
log line nor are there any artifacts in the target
folder associated with time
.
I checked various issues and documentation entries, but I couldn't find if this is a bug or intended.
The tracking issue (#8832) and documentation (https://doc.rust-lang.org/nightly/cargo/reference/features.html#dependency-features) do not mention any changes in to Cargo.lock
. Neither does the implementation PR (#8818), which does not even seem to have any lock files.
Version
cargo 1.62.0 (a748cf5a3 2022-06-08)
release: 1.62.0
commit-hash: a748cf5a3e666bc2dcdf54f37adef8ef22196452
commit-date: 2022-06-08
host: x86_64-unknown-linux-gnu
libgit2: 1.4.2 (sys:0.14.2 vendored)
libcurl: 7.80.0-DEV (sys:0.4.51+curl-7.80.0 vendored ssl:OpenSSL/1.1.1n)
os: OracleLinux 36.0.0 [64-bit]
FYI: My OS is Fedora 36, but this is the output of `cargo version --verbose`.