Skip to content
Closed
150 changes: 105 additions & 45 deletions src/doc/src/reference/specifying-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,85 +2,106 @@

Your crates can depend on other libraries from [crates.io] or other
registries, `git` repositories, or subdirectories on your local file system.
You can also temporarily override the location of a dependency — for example,
to be able to test out a bug fix in the dependency that you are working on
locally. You can have different dependencies for different platforms, and
dependencies that are only used during development. Let's take a look at how
to do each of these.

It's possible to temporarily change the version or path of a dependency, this
can be useful for checking the new features or bug fixes after some major
release.

You can specify different dependencies for:
- Development and release profiles.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what is meant is meant here, but it seems to imply you can independently define dependencies for different profiles (which can't be done). Can you say why this is mentioning profiles here?

Copy link
Author

@marcospb19 marcospb19 Dec 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mistaken in this one, glad you got my mistake in the review.

Rewritten to:

Dependencies can be specified for [crate features](features.md) and for
different [architectures and operating systems](#platform-specific-dependencies).

- Different platforms, architectures and operating systems.
- Crate "features" that can be enabled and disabled.

### Specifying dependencies from crates.io

Cargo is configured to look for dependencies on [crates.io] by default. Only
the name and a version string are required in this case. In [the cargo
guide](../guide/index.md), we specified a dependency on the `time` crate:
Here is an example of the most common method for specifying dependencies:

```toml
[dependencies]
time = "0.1.12"
```

The string `"0.1.12"` is a [semver] version requirement. Since this
string does not have any operators in it, it is interpreted the same way as
if we had specified `"^0.1.12"`, which is called a caret requirement.
Cargo looks for dependencies on [crates.io] by default. For this case, it only
requires the name and a version string.

The strings `"0.1.12"` is a [semver] version requirement, and since it does not
contain any extra operators, it is interpreted as the caret requirement
`"^0.1.12"`, so that line will download the crate `time` with a version that is
compatible with `0.1.12` following the Caret requirement rules.

There are five types of version requirements:

Type | Operators | Examples
-------|-------|-------
Caret | None or `^` | `"1.2.3"` and `"^1.2.3"`
Tilde | `~` | `"~1.2.3"`
Wildcard | `*` | `"1.2.*"`
Comparison | `>`, `<` and `>=` | `">1.2.3"`, `"<1.2.3"` and `">=1.2.3"`
Strict | `=` | `"= 1.2.3"`

[semver]: https://github.com/steveklabnik/semver#requirements
[semver]: https://github.com/dtolnay/semver
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolved question: where was this pointing to? The previous repository now leads to this new one I inserted, but there is no section "#requirements".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it used to summarize the rules for requirements, but that has been removed and instead points to this page (somewhat circular).

I notice this page doesn't link to or describe what SemVer is anywhere. Perhaps it could link to https://semver.org/ and/or https://doc.rust-lang.org/cargo/reference/resolver.html#semver-compatibility?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to https://doc.rust-lang.org/cargo/reference/resolver.html#semver-compatibility, because it already points to https://semver.org/ in the first line.

So it's like we're pointing to both.


### Caret requirements

**Caret requirements** allow SemVer compatible updates to a specified version.
An update is allowed if the new version number does not modify the left-most
non-zero digit in the major, minor, patch grouping. In this case, if we ran
`cargo update -p time`, cargo should update us to version `0.1.13` if it is the
latest `0.1.z` release, but would not update us to `0.2.0`. If instead we had
specified the version string as `^1.0`, cargo should update to `1.1` if it is
the latest `1.y` release, but not `2.0`. The version `0.0.x` is not considered
compatible with any other version.
**Caret requirements** allow SemVer compatible updates, it's the only
requirement type that uses specific rules for versions with and without the zero
digits.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused by this statement about the zero digits.

Usually I think it is best to have a definition up front when introducing a term, and I think it would be good to lead with the sentences that define its left-most non-zero behavior. I think the wording here is very important since this is introducing a potentially confusing topic, and this is one of the most important parts of cargo. If possible, it would be best to try to approach it assuming you don't know what semver is, or what a version requirement is and what it means. The original text tried to do that by introducing a topic by example from the perspective of what someone does with these dependencies. I'm not saying it has to use that style, just mentioning that is one way to introduce a new concept.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I rewrote this section and now the definition comes first, needs another review.


Updates are only allowed if the new version number does not modify the left-most
non-zero digit, so the version `0.0.x` is not considered compatible with any
other version.

If we specify the version string as `"1.0.4"`, compatible versions are, `1.0.x`
where `x` is greater than 4.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don' tthink this is correct. Specifying "1.0.4" means that it will pick any version 1.x.y greater than 1.0.4.

Copy link
Author

@marcospb19 marcospb19 Dec 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this to be a bit hard to explain without being confusing and verbose.

I tried organizing this in another way, here's what I came up with:

If we specify the version string as `"1.4.8"`, compatible versions are:
- `"1.4.x"` with `x ≥ 8`.
- `"1.x.y"` with `x > 2`, `y` can be anything.

What do you think?


If we specify the version string as `"1.4"`, compatible versions are, `1.x.y`
where `x` is greater than 4 and `y` is anything.

Here are some more examples of caret requirements and the versions that would
be allowed with them:

```notrust
^1.2.3 := >=1.2.3, <2.0.0
^1.2 := >=1.2.0, <2.0.0
^1 := >=1.0.0, <2.0.0
^0.2.3 := >=0.2.3, <0.3.0
^0.2 := >=0.2.0, <0.3.0
^0.0.3 := >=0.0.3, <0.0.4
^0.0 := >=0.0.0, <0.1.0
^1.2 := >=1.2.0, <2.0.0
^1.2.3 := >=1.2.3, <2.0.0
^0 := >=0.0.0, <1.0.0
^0.0 := >=0.0.0, <0.1.0
^0.0.3 := >=0.0.3, <0.0.4 (exact)
^0.2 := >=0.2.0, <0.3.0
^0.2.3 := >=0.2.3, <0.3.0
```

This compatibility convention is different from SemVer in the way it treats
versions before 1.0.0. While SemVer says there is no compatibility before
1.0.0, Cargo considers `0.x.y` to be compatible with `0.x.z`, where `y ≥ z`
and `x > 0`.
and `x` is not zero.

### Tilde requirements

**Tilde requirements** specify a minimal version with some ability to update.
If you specify a major, minor, and patch version or only a major and minor
version, only patch-level changes are allowed. If you only specify a major
version, then minor- and patch-level changes are allowed.
If you specify a string with minor or patch version, only patch-level changes
are allowed. If you only specify a major version, then minor-level changes are
also allowed.

`~1.2.3` is an example of a tilde requirement.
Examples:

```notrust
~1.2.3 := >=1.2.3, <1.3.0
~1.2 := >=1.2.0, <1.3.0
~1 := >=1.0.0, <2.0.0
~1 := >=1.0.0, <2.0.0
~1.2 := >=1.2.0, <1.3.0
~1.2.3 := >=1.2.3, <1.3.0
```

### Wildcard requirements

**Wildcard requirements** allow for any version where the wildcard is
positioned.

`*`, `1.*` and `1.2.*` are examples of wildcard requirements.
Examples:

```notrust
* := >=0.0.0
1.* := >=1.0.0, <2.0.0
1.2.* := >=1.2.0, <1.3.0
* := >=0.0.0
1.* := >=1.0.0, <2.0.0
1.2.* := >=1.2.0, <1.3.0
```

> **Note**: [crates.io] does not allow bare `*` versions.
Expand All @@ -90,19 +111,58 @@ positioned.
**Comparison requirements** allow manually specifying a version range or an
exact version to depend on.

Here are some examples of comparison requirements:
Examples:

```notrust
>= 1.2.0
> 1
< 2
= 1.2.3
>1.2
<2
>=1.2.0
>=1.2.0, <1.3.0
>=1.2.2, <1.2.5
```

### Multiple requirements

As shown in the examples above, multiple version requirements can be
separated with a comma, e.g., `>= 1.2, < 1.5`.
As shown in the examples above, it is possible to combine any requirements to
restrict the version even further, however, this is only necessary with
[comparison requirements](#Comparison-requirements).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Section fragments should be in lower case.

Suggested change
[comparison requirements](#Comparison-requirements).
[comparison requirements](#comparison-requirements).

Also, I would maybe include what it means to combine requirements, both the syntax and the semantics. That is, saying that you can combine multiple requirements with commas, and that it means that all requirements must be met.

Copy link
Author

@marcospb19 marcospb19 Dec 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed the section upper case and added this text to the multiple requirements part:

The list of requirements should be separated by commas, spaces are optional.

A version is considered to be compatible with the list only if it is compatible
with all elements of the list.


Examples (all of them are equivalent):

```notrust
1.0.0, < 1.0.5
^1.0.0, < 1.0.5
~1.0.0, < 1.0.5
>=1.0.0, < 1.0.5
=1.0 , < 1.0.5
```

Example using the `time` crate:
```toml
[dependencies]
time = ">=0.2.7, <0.2.15"
```

### Strict version requirements

**Strict version requirements** allow you to lock the numbers for major, minor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little uneasy introducing this as a separately defined kind of requirement. For example =1 is not what I would characterize as "strict". Is there a particular reason for adding it? It seems like it fits with the comparison section, as = is a comparison operator.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning was that strict requirements only unique purpose is specifying exact versions without having to create a list of multiple requirements.

For example, =1.2.3 is a shorthand for >= 1.2.3, < 1.2.4.

And the other comparison operators all leave open ranges to be combined with more operators, = on the other hand, works very similarly to *, specifying a part of the version, and having the missing parts be "anything".

and patch versions. You can specify the exact version if the patch part is
given.

Here are some examples:

```notrust
=0 := >=0.0.0, <1.0.0
=0.1 := >=0.1.0, <0.2.0
=0.1.2 := >=0.1.2, <0.1.2 (exact)
=1 := >=1.0.0, <2.0.0
=1.2 := >=1.2.0, <1.3.0
=1.2.3 := >=1.2.3, <1.2.4 (exact)
```

> **Note**: Using strict requirements with exact versions are a bad practice and
> should be avoided, as it disables the ability of receiving important patches
> of security, soundness and bugfixes.
Copy link
Author

@marcospb19 marcospb19 Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the advice you suggested, about the hazard of using strict requirements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not word this so strongly. This goes against the advice given in https://doc.rust-lang.org/cargo/reference/resolver.html#recommendations where exact requirements do have some use cases (for example, serde has an exact semver requirement on serde_derive because the two are very tightly coupled and not intended to be used independently.

There are other use cases, such as a temporary workaround to lock to an exact version. I think we've done that with cargo itself before.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to:

> **Note**: When using strict requirements with exact versions, no updates can
> be applied, including bugfixes and security updates.

Any other recommendations?


### Specifying dependencies from other registries

Expand Down