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:
- The crate should build a dummy/no-op version of itself "out-of-the-box" on the architectures it doesn't work on.
- 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 name | rust arch name (target_arch) |
---|---|
Arches autopkgtest runs on (needed for testing migration) | |
amd64 | x86-64 |
i386 | x86 |
arm64 | aarch64 |
armel | arm |
armhf | arm |
ppc64el | powerpc64 |
s390x | powerpc64? s390x? |
riscv64 | riscv64 |
Other official arches 1 | |
mips64el | mips64 |
Unoffical ports with rustc/cargo (not really relevant) | |
powerpc | powerpc? |
loongarch64 | loongarch64? |
ppc64 | powerpc? |
sparc64 | sparc64? |
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"))]
.
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:
- 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. - 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
- https://blog.hackeriet.no/packaging-a-rust-project-for-debian/
- https://blog.hackeriet.no/packaging-rust-part-II/
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.