Rust version strings¶
The Rust version string format used in the Ubuntu archive is complicated and contains certain unique features. It’s a combination of Debian policy, Ubuntu conventions, and legacy code. Although you will usually change only a few parts of the version string, it’s a good idea to know what all of it means.
Important
An understanding of how Ubuntu version strings normally work is mandatory before this article can be read.
Typical Rust version string¶
Components in [square brackets] are placeholders to be filled in, while components in <angle brackets> are optional.
The version string format for a versioned rustc-X.Y source package is as follows:
[upstream_version]+dfsg<[repack_number]>-0ubuntu[ubuntu_revision]
[upstream_version]¶
This component shows what upstream version of the Rust toolchain this package is. Since Ubuntu Rust toolchain packages are versioned, this number only changes if the upstream Rust Foundation releases a patch for the current release, e.g., 1.85.0 -> 1.85.1.
If the Rust Foundation releases a new patch release, then the rest of the version number gets reset back to +dfsg-0ubuntu1.
Example:
1.85.0+dfsg3-0ubuntu5->1.85.1+dfsg-0ubuntu1
+dfsg<[repack_number]>¶
This component signifies that the original upstream source has been modified from its original state, i.e., the orig tarball has been repacked.
The +dfsg component is always there because during the rustc update process, several unneeded dependencies are pruned from the upstream source.
Normally, the [repack_number] can be elided entirely. However, if after the first release the orig tarball must be repacked for whatever reason, a [repack_number] must be added afterwards, starting at 1.
If this number must be incremented, then the [ubuntu_revision] (described in -0ubuntu[ubuntu_revision]) must be reset back to 1.
Example:
1.85.1+dfsg-0ubuntu3->1.85.1+dfsg1-0ubuntu1
Here are some examples of this component:
Component |
Meaning |
|---|---|
|
This tarball has not been modified since the initial package upload. |
|
This tarball has been modified after the original package upload. |
|
This tarball has been modified twice. |
-0ubuntu[ubuntu_revision]¶
Finally, this component shows how many modifications the Ubuntu maintainers have made to this Rust toolchain. For the first upload, [ubuntu_revision] starts at 1.
The ‘0’ in the 0ubuntu[ubuntu_revision] component signifies that this package is separate from Debian and is never synced.
If the [<repack_number>] described above is ever added or incremented, [ubuntu_revision] is reset back to 1.
Examples of this component:
Component |
Meaning |
|---|---|
|
Initial upload for the given upstream source. |
|
The third Ubuntu revision for the given upstream source. |
Example: Uploading and updating a new Rust toolchain¶
Situation |
Action |
Version string |
|---|---|---|
Initial upload |
Use the default |
|
Fixing a bug |
Increment |
|
Pruning an unwanted dependency accidentally included in the orig tarball |
Add a |
|
Upstream (Rust Foundation) creates a patch release for Rust 1.95 |
Update the |
|
Uploading another Ubuntu-specific fix |
Use new |
|
Rust backport version string¶
A backported Rust toolchain follows the same rules as a normal upload, with a few modifications:
[upstream_version]+dfsg<[repack_number]><~[repack_series]<.[backport_repack]>>-0ubuntu0.[series_number].[ubuntu_revision]
<~[repack_series]<.[backport_repack]>>¶
During backporting, there are certain cases in which the Rust toolchain’s dependencies can’t be met because the archive is too old. When this happens, the dependencies must be vendored, i.e., included in the orig tarball. (This commonly happens with LLVM and libgit2.)
If this is necessary, the existing [repack_number] is untouched. Instead, ~[repack_series] is added, which shows that the tarball has been repacked for this specific Ubuntu series.
If, after the initial backport upload, the orig tarball must be modified again, .[backport_repack] is added and incremented as necessary.
Examples of this component:
Component |
Meaning |
|---|---|
|
The orig tarball is the same as the original upload. |
|
The orig tarball was modified for a 22.04 backport. |
|
The orig tarball, revised in the original upload, was also modified for a 24.04 backport. |
|
The orig tarball had to be modified for a 25.10 backport, then revised later. |
-0ubuntu0.[series_number].[ubuntu_revision]¶
We don’t want the backport version number to sort newer than any non-backported version in the archive. Therefore, the original Ubuntu revision is replaced by 0.[series_number].[ubuntu_revision].
The [series_number] signifies the particular series this backport targets.
The [ubuntu_revision] component acts just like the standard [ubuntu_revision] component — it starts at 1 and is incremented as necessary.
Here are some examples of this component:
Component |
Meaning |
|---|---|
|
This is the initial upload of the 22.04 backport. |
|
This 20.10 backport has been revised once after the initial upload. |
Example: Backporting a Rust toolchain¶
Let’s say you need to backport the 1.90.0+dfsg2-0ubuntu3 Rust toolchain to Ubuntu 24.04:
Situation |
Action |
Version string |
|---|---|---|
No need to modify the orig tarball |
Add |
|
Fixing a bug |
Increment |
|
Backporting to 22.04 with vendored LLVM (modifying the orig tarball) |
Add |
|
Backporting to 20.04 (no modifications to 22.04 tarball) |
Keep |
|
Backporting to 18.04 with added vendored |
Change |
|
Fixing an issue with the 18.04 repack |
Add |
|
Legacy version string format¶
Important
This format is no longer used!
It’s possible you may need to work with older versions of the Rust toolchain with potentially confusing version strings. While these formats are no longer used, they should help one understand the version strings of these older toolchains.
Here, <angle_brackets> indicate placeholders to be edited, while [square_brackets] indicate optional parts.
<rust_version>+dfsg0ubuntu<repack>[~bpo<vendored_dependencies>]-0ubuntu<revision>.[<ubuntu_release>][~ppa<PPA>]
<rust_version>¶
The upstream Rust toolchain version.
This is simple; it’s just the upstream version of the given Rust toolchain. It’s only updated when adding a new Rust version to the archive.
Examples:
1.88.0+dfsg0ubuntu1-0ubuntu1~ppa1: Rust 1.88.01.87.0+dfsg0ubuntu1-0ubuntu1: Rust 1.87.01.85.1+dfsg0ubuntu2-0ubuntu2~ppa3: Rust 1.85.11.80.0+dfsg0ubuntu1~bpo2-0ubuntu0.24.09~ppa4: Rust 1.80.0
+dfsg0ubuntu<repack>¶
The number of times you have edited Files-Excluded.
dfsg is short for “Debian free software guidelines.”
The presence of +dfsg<whatever> in any package indicates that the orig tarball has been repacked in some way.
Usually, this is done for copyright reasons. However, in this case, we are doing it to make our tarballs smaller. Rust comes with a lot of functionality that we don’t need, most notably Windows support. To save space, we use Debian’s ability to exclude all those unnecessary files from the tarball. That way, we aren’t hauling around megabytes of code the compiler is going to ignore anyways.
Returning to +dfsg0ubuntu<repack>, since we don’t use Debian’s upstream package, the number after dfsg shall always be 0, because Debian won’t have repacked the tarball.
We (ubuntu) have repacked it <repack> times.
Since we always repack the tarball when updating the Rust version, a newly-released versioned Rust package will always use +dfsg0ubuntu1.
Note
The How to update Rust docs instruct you to start with +dfsg0ubuntu0 in the version number.
This is because it’s simply an interim number that will be replaced with +dfsg0ubuntu1 once the package is ready for upload.
Examples:
1.88.0+dfsg0ubuntu1-0ubuntu1~ppa1: 1st repack1.87.0+dfsg0ubuntu1-0ubuntu1: 1st repack1.85.1+dfsg0ubuntu2-0ubuntu2~ppa3: 2nd repack1.80.0+dfsg0ubuntu1~bpo2-0ubuntu0.24.09~ppa4: 1st repack
[~bpo<vendored_dependencies>]¶
Code number for what dependencies are vendored.
This portion of the version string is applicable to backports only. More info on Rust backports can be found in How to backport Rust.
If you have vendored LLVM or libgit2 for your backport, then you must include this part.
Otherwise, then this portion must be omitted entirely.
<vendored_dependencies> is a code number:
0whenlibgit2and LLVM are vendored2when only LLVM is vendored, and the systemlibgit2is used10when onlylibgit2is vendored, and the systemLLVMis used
Examples:
1.88.0+dfsg0ubuntu1-0ubuntu1~ppa1: No vendored dependencies1.87.0+dfsg0ubuntu1-0ubuntu1: No vendored dependencies1.85.1+dfsg0ubuntu2-0ubuntu2~ppa3: No vendored dependencies1.80.0+dfsg0ubuntu1~bpo2-0ubuntu0.24.09~ppa4: Only LLVM is vendored1.83.0+dfsg0ubuntu1~bpo0-0ubuntu0.24.09~ppa1: Bothlibgit2and LLVM are vendored
0ubuntu<revision>¶
The “real” version.
This is the component that actually indicates the number of times you have edited this particular package. Every time you need to edit a particular version of Rust on a particular version of Ubuntu, you increment this number.
<revision> starts at 1.
When creating a new Rust release package for the archive, this portion will always be 0ubuntu1 upon upload to the archive.
Note
The How to update Rust docs instruct you to start with 0ubuntu0 in the version number.
This is because it’s simply an interim number that will be replaced with 0ubuntu1 once the package is ready for upload.
When updating an existing Rust toolchain in the archive, <revision> will be incremented.
This number gets reset back to 1 whenever ‘repack’ is incremented.
For example, repacking 1.82.0+dfsg0ubuntu1-0ubuntu3 means the new version number would be 1.82.0+dfsg0ubuntu2-0ubuntu1.
Examples:
1.88.0+dfsg0ubuntu1-0ubuntu1~ppa1: First Revision1.87.0+dfsg0ubuntu1-0ubuntu1: First Revision1.85.1+dfsg0ubuntu2-0ubuntu2~ppa3: Second Revision (#2)
[<ubuntu_release>]¶
The Ubuntu release in case of backport, plus some hacks.
This portion of the version string is applicable to backports only. More info on Rust backports can be found in How to backport Rust.
In theory, this part is simple: it’s the number of the Ubuntu release this backport is for. In practice, however, there’s a catch; while the backport is a work-in-progress, decrement the last number by 1. That way it always sorts before the finalized version.
This portion is omitted entirely if this is not a backport.
Examples:
1.88.0+dfsg0ubuntu1-0ubuntu1~ppa1: Not a backport1.87.0+dfsg0ubuntu1-0ubuntu1: Not a backport1.80.0+dfsg0ubuntu1~bpo2-0ubuntu0.24.09: WIP, for Ubuntu 24.10 (that’s Oracular Oriole)1.83.0+dfsg0ubuntu1-0ubuntu1.24.03~ppa3: WIP, for Ubuntu 24.04 (that’s Noble Numbat)1.83.0+dfsg0ubuntu1~bpo0-0ubuntu1.24.04: Complete, for Ubuntu 24.04 (again, Noble Numbat)
[~ppa<PPA>]¶
The number of times you have pushed it to your PPA for testing.
Every time you make some changes, and want to check that it builds and passes tests by pushing it to your PPA, you should increment this number. This is because Launchpad does not let you “re-upload” a version with the same version string but different source code. Thus you have to make the version string different for each PPA upload. This is our convention for doing that.
Every time you change the rest of the version string in some way, you can reset this to 1.
If this part is not present, that means it’s on the main archive, so it’s a version that’s actually out.
Note
Changelog (debian/changelog) entries with ~ppa<PPA> should never make it onto a version control system; they are only for the benefit of the PPA itself.
When working on a Rust toolchain locally, the PPA-specific changelog entry (and version string) should be removed after successful PPA upload.
Examples:
1.88.0+dfsg0ubuntu1-0ubuntu1~ppa1: First push to your PPA1.87.0+dfsg0ubuntu1-0ubuntu1: No PPA (i.e., real complete release)1.85.1+dfsg0ubuntu2-0ubuntu2~ppa3: 3rd push to your PPA
Putting it all together¶
To recap, let’s do a complete breakdown of some example version strings:
String |
|
|
|
|
|
|
|---|---|---|---|---|---|---|
|
1.80.0 |
1 |
2, so only LLVM |
0 |
In-dev backport for 24.10 (OO) |
4 |
|
1.88.0 |
1 |
System libgit2 and LLVM |
1 |
Omitted b/c this is a normal port |
1 |
|
1.83.0 |
2 |
0, so both libgit2 and LLVM |
1 |
In-dev backport for 24.03 (NN) |
3 |