Upstream Guidelines
This section of the Rust team book gives a quick overview over things upstream developers can do (or should not do) to make packaging their crates / projects written in Rust easier for Linux distributions like Debian. Most the the tips here will also improve the robustness outside of distribution related packaging efforts, e.g. by extending test exposure which often finds issues/buggy behaviour.
We actively invite upstreams to give us feedback on these guidelines!
Applicable to all crates / Rust code
Run your CI on something other than x86_64/aarch64
Debian is released on a wide range of architectures, with an even bigger set covered by its "Ports" effort. Running CI on at least a 32-bit architecture, possibly even one with Big-Endian support helps discover portability issues.
Run your CI with non-default feature combinations
Debian packages (by default) will test the following feature combinations when a crate is packaged:
- all features enabled
- no features enabled
- the default features enabled
- each feature enabled on its own, with default features disabled
Many crates exhibit test suite failures when tested in this fashion, usually
caused by missing #[feature] annotations in the test (or regular) code.
Ensure your test suite can run as published on crates.io
Debian uses the published crate tarball from crates.io as input for packaging.
If this published version of the crate is lacking test input data, or the test suite relies on test helper crates which are not published, some or all of the tests cannot be run as part of the packaging effort. The resulting package will have a higher chance of being buggy as a result.
If it is absolutely not possible to publish the full test suite, please ensure
that cargo test does work on the published crate nevertheless.
Avoid dependencies on alpha/../pre-release versions
Unless your crate is currently itself released with an alpha/../pre-release version, do not use such versions of your dependencies. Distributions will (usually) not package such versions since they are not ready for release yet.
Avoid nightly/unstable features
Unless absolutely required, do not rely on nightly or unstable compiler features or crates that require them. If you do, please make it possible to disable such requirements by patching out features.
Packaged toolchains do not support such features.
Avoid duplicate dependency versions in your dependency tree
Having multiple incompatible versions of a crate in your transitive dependency tree makes transitions in distributions harder.
Be conservative with MSRV, dependency versions and semver breaks
Distributions will usually not have the latest version of the toolchain or crates already packaged. By being conservative with MSRV bumps, tracking the actually required minimum versions of dependencies instead of blindly bumping to the latest, and avoiding frequent semver-breaking version bumps of your crate(s) you can help keeping downstream patching and churn to a minimum.
Having a documented MSRV policy will also help packages when considering whether to package your particular crate/project.
Document which features are considered part of your public crate interface
Documenting features which only exist for technical reasons (like usage in CI, fuzzing, ..) or are considered unstable and not covered by semantic versioning both helps potential dependants and distribution packagers.
In general, try to keep the amount of features reasonable, and ensure you use the correct syntax to avoid exposing optional dependencies as features by accident.
Specific for -sys / FFI crates
Bundled C (library) source code
Many -sys crates include a copy of the library they are linking with. These sources are usually stripped by distribution packagers, since distributions want to link (only) with the version of the library shipped in distribution packages.
Ensuring that there is an easy, tested way of building in the absence of bundled sources makes packaging and updating such crates a lot easier.
Pre-generated bindings
For similar reasons, pre-generated bindings are usually regenerated at package build time in distributions. Ensuring that there is an easy, tested way of regenerating bindings makes packagers' lifes easier.
Cross-building
If possible, testing cross-builds and trying to make them work out of the box will allow easier bootstrapping of new architectures.
Specific for applications written in Rust
Generate and ship a man page for CLI applications
If using clap, this can be done using clap_mangen. Writing a man page
manually is also an option. Generating it from --help output usually means
breaking cross builds, unless it is done via test/CI and not as part of the
regular build.
Generate and ship shell completions for CLI applications
Similar considerations as for man pages apply. For crates using clap, this
can be done using clap_complete.