Packaging workspaces, crates not published on crates.io, and projects being partly written in Rust
Certain projects pack tens of internal crates in a workspace. Some of them still publish on crates.io, but it's quite a hassle to package them one by one with the single crate process, not to mention maintaining them in sync later; some don't, often seen in projects that build programs - these internal crates see no use outside.
Thus, there is a desire to package such projects as a single source package, and either each library crate as a binary package, or only one or few binary package(s) packing the built program(s).
We are still exploring ways to build them. Recorded here are some existing practices, not team recommendations.
For programs, it doesn't matter if the crates are not published on crates.io. For libraries not on crates.io, however, their package name scheme has yet to be decided, since the librust-*-dev namespace is reserved for libraries from crates.io. Luckily, there is currently no need to.
General setup
This kind of packaging falls back to "traditional" ways in Debian. This assumes you are already familiar with general Debian packaging. Experience with the single crate process isn't strictly needed but is helpful.
- Import upstream source by either cloning the upstream repository,
gbp import-orig
, or ways you prefer. - Prepare the common things in debian/ as usual.
- Check packaging status of dependencies. There is currently no ready-made
tool for this, but you can gather all
[dependencies]
,[dev-dependencies]
, and[build-dependencies]
in Cargo.toml of these internal crates into an empty cargo project, and run cargo-debstatus there. - Add them as
Build-Depends
along withrustc
andcargo
in debian/control (you might usedebcargo deb-dependencies Cargo.toml
as a starting point) - Choose a build approach: there is dh-rust which seemingly supports workspaces, there is dh-cargo which doesn't yet but works fine for single crates (example), and there is a semi-manual approach for other programs or projects not written in pure Rust (example #1, example #2).
- Patch the source as needed.
No need to publish internal crates
This is the easy part. After adding needed dependencies as B-D, patching them to use versions in Debian, patching out unavailable dependencies and feature depending on them, use one of the debhelper buildsystems described above.
Publish internal crates
Consider these situations:
- Crates in workspace are released in lockstep, sharing the same version for each release.
- They only reside in a workspace, but are released in their own pace.
There's not much to say about (1). For (2), though, there is a problem: the
source package, or the workspace, has a version. Each binary package, or crate,
also has their own version. The only known way to achieve this is to
dpkg-gencontrol
/dh_gencontrol
for each binary package; see
rust-curve25519-dalek for an example.
Currently, use dh-rust. dh-cargo has no workspace support yet.
Add a Package
stanza for each of them in debian/control, which Provides
their versioned feature virtual packages. Policy states which are
needed.
Then it's the tiresome work of keeping B-Ds, Package
s, and Depends
in sync.
There hasn't been strong urge to write a tool for this.
Manual wrapper approach
In case you are packaging a complex application or shared library written in
Rust, or a project combining Rust with other languages, and do not need to
package the contained Rust source code as librust-xxx-dev
package, consider
using the cargo
wrapper in /usr/share/cargo/bin/cargo
together with some
setup in debian/rules
.
You can setup the environment variables like this:
include /usr/share/dpkg/default.mk
include /usr/share/rustc/architecture.mk
export DEB_HOST_RUST_TYPE
export DEB_HOST_GNU_TYPE
export PATH := /usr/share/cargo/bin:$(PATH)
export CARGO=/usr/share/cargo/bin/cargo
export CARGO_HOME=$(CURDIR)/debian/cargo_home
export DEB_CARGO_CRATE=$(DEB_SOURCE)_$(DEB_VERSION_UPSTREAM)
and prepare the cargo wrapper for packaging usage like this:
execute_before_dh_auto_configure:
/usr/share/cargo/bin/cargo prepare-debian debian/cargo_registry --link-from-system
This invocation will prepare a cargo config file for the package build,
pointing at a local registry directory instead of crates.io
. It will also
ensure that debug symbols are included in built binaries, optimization and LTO
flags set by the builder are honored and that the correct target is selected
even when cross-building.
Depending on the build system used, you might need to add additional compat symlinks
or instructions to ensure every tool involved in the build picks up the correct
target
directory and calls the cargo
wrapper instead of the "real" cargo
.
Finally, do not forget to call dh-cargo-built-using
to emit Built-Using
and
Static-Built-Using
substvars at the end of the build:
execute_after_dh_auto_install:
/usr/share/cargo/bin/dh-cargo-built-using <MAIN PACKAGE NAME>
and include them in the debian/control
file.