General packaging tips

Disabling things in Cargo.toml

Dependencies, tests, examples, or benchmarks often need to be disabled in Cargo.toml. They used to be commented out or removed entirely:

-[[bench]]
-name = "file"
-path = "benches/file.rs"
+#[[bench]]
+#name = "file"
+#path = "benches/file.rs"
-[[bench]]
-name = "file"
-path = "benches/file.rs"

People have different ideas on these two approaches: some think removal is acceptable since patches are shipped along, some think comments are more obvious to users.

They are both cumbersome and complicates future updates, though. For blocks, here is a simpler way:

-[[bench]]
+[[disabled.bench]]

Individual lines still need to be removed or commented out, unfortunately.

package.metadata is safe to ignore

As the name suggests, this table is metadata, more specifically, "Extra settings for external tools."

Disabling things in Rust code

As for Cargo.toml, commenting things out with /* */ and // used to be a common approach. There is also a simpler way:

 #[test]
+#[cfg(any())]
 fn test() {

The cfg() macro enables the item only when the conditions in it are met; any() is true when, well, any thing in it is met, but there is none! So it's never met, essentially disabling the code.

But note, this completely erases that thing; depending on the situation, this might not be wanted.

For tests, it could be changed to #[ignore]: the test is still there, but ignored; ignored tests can be manualy run with cargo test -- --ignored.

 #[test]
+#[ignore = "the ignore macro can also show a comment about the situation"]
 fn test() {

For non-test code, cfg(any()) could be changed to something that normally is not met, for example cfg(only-enabled-through-a-flag), which is enabled through a --cfg only-enabled-through-a-flag argument to rustc.

Tests and examples

Usually tests and examples are run, to make sure they work in Debian. Examples are a good complement to tests.

However, when they are flaky, lack test data (some upstreams exclude them when publishing to crates.io), or lack resources (privileged or otherwise unavailable on Debian infrastructure, the most common being network access), they must be disabled.

If not explicitly listed as [[test]] and [[example]] blocks, they can be lumpsum disabled with this under the [package] section (if not already set by upstream):

+autotests = false
+autoexamples = false

Some tests take too long to run on certain architectures. They could be patched to not run there, avoiding timeout failures:

 #[test]
+#[cfg(not(target_arch = "riscv64"))] // too slow
 fn test() {

Skipping doctests

In case doctests get run during the build process and you want to disable them add the following lines in Cargo.toml (as patch):

+[lib]
+doctest = false

They often fail so you can safely disable them that way. Example: xdg-home, rust-apt

Benchmarks

Benchmarks help upstream keep track of the performance of their work. There is generally no need to run them in Debian. Try to disable them in Cargo.toml, by setting autobenches = false in the [package] section if not already set, and disabling [[bench]] entries.

OS-specific crates

See redox-syscall for examples on how to deal with these.

If this is unclear, ask on IRC.

Architecture-specific crates

This is a bit harder. Usually there are two options:

  1. The crate should build a dummy/no-op version of itself "out-of-the-box" on the architectures it doesn't work on.
  2. Dependent crates should depend on it with a platform-specific dependency.

(1) involves less burden for others, both for dependent crates and for us packagers, since overriding d/rules isn't needed to ignore test failures on non-working architectures. You should communicate to upstream that this is the preferred approach.

In the case of (2), the crate should document exactly what conditional should be used, and keep this documentation up-to-date. This allows us to easily determine if dependent crates are using the correct conditional. You will then have to override d/rules for this crate, see src/simd for an example.

You should file a bug upstream if the crate does neither (1) nor document the conditions for (2), e.g. https://github.com/hsivonen/simd/issues/25

(Actually the above applies even for "OS-specific crates" but then (2) is obvious so documentation is less necessary, and dependent crates all do it correctly already.)

Arch-specific failures

It can rarely happen that tests (read: autopkgtest) fail on specific arches because how bytes are addressed on that arch. The best course of action is to investigate first if it indeed is an arch-specific failure. If that's the case you need to write a patch that skips those faulty tests (on that arch) so the package can enter testing. Because arch names are different in rust, here is a handy table comparing them:

Debian arch namerust arch name (target_arch)
Arches autopkgtest runs on (needed for testing migration)
amd64x86-64
i386x86
arm64aarch64
armelarm
armhfarm
ppc64elpowerpc64
s390xpowerpc64? s390x?
riscv64riscv64
Other official arches 1
mips64elmips64
Unoffical ports with rustc/cargo (not really relevant)
powerpcpowerpc?
loongarch64loongarch64?
ppc64powerpc?
sparc64sparc64?
x32?

Arches without rustc/cargo:

  • sh4 2
  • alpha
  • arc
  • hppa
  • hurd-i386
  • ia64
  • m68k

Only the first seven are really relevant, the rest are included for completeness's sake.

If you encounter a test failure e.g. on armel, add this macro before the #[test] macro:

#![allow(unused)]
fn main() {
#[cfg(not(target_arch = "arm"))]
}

Then generate a patch with the changes and include it in the usual way. Also notify upstream that this arch is broken and send them your patch.

To skip a test on e.g. all big-endian arches you can use something like #[cfg(not(target_endian = "big"))].

2

sh4 has only one test failure for cargo

ITPs

File ITPs (Intent to Package) for user-facing things, e.g. programs, as usual.

For libraries, the Rust team used to consider it a hassle and spam to the bug tracker, while some disagreed. The team now starts to file ITPs for libraries with a big stack of crates too, in order to ease coordination and tracking of efforts.

Binary crate ([[bin]]) has required-features

TODO: see if it actually requires manual handling.

Binary (crate) name conflicts with other package

There are two ways to handle this:

  1. Patch the name of the [[bin]] in Cargo.toml to something else, commonly "thing-rs". This changes both the binary name and the binary package name.
  2. Install it to another location with the same name, and/or install it as another name, then let the user choose to alias/link it. The fd-find package does both: /usr/lib/cargo/bin/fd and /usr/bin/fdfind.

Patch headers

DEP 3 formalized a set of patch headers. Use them accordingly to explain why a patch exists. quilt header -e --dep3 opens $EDITOR with a template.

Dependencies on clippy

Clippy is a linting tool, run by developers. Crates normally don't need to depend on it to function. If grepping its name shows only cfg_attr macros, it can safely be removed. If there are use statements, and the code heavily relies on it, then leave it be.

Some ramblings

In #debian-rust came these two blog posts along with the remark of good read

Now are they, those two blog posts, parked here. Waiting for better integration.

Developing Rust code using Debian-packaged crates

While perhaps not the stated intention, the Rust ecosystem in Debian is actually quite usable for developing Rust code in general. Thanks to source replacement, Cargo can be configured to use only local, Debian-provided packages by placing something like the following in ~/.cargo/config.toml (for user-wide effect) or in a given project's .cargo/config.toml:

[net]
offline = true

[source]

[source.crates-io]
replace-with = "debian"

[source.debian]
directory = "/usr/share/cargo/registry"

In this state, Cargo will only look for crates installed as Debian packages on the local system.