kornelski / cargo-deb

A cargo subcommand that generates Debian packages from information in Cargo.toml
https://lib.rs/cargo-deb
MIT License
404 stars 48 forks source link
debian debian-packaging deployment rust

Debian packages from Cargo projects

This is a Cargo helper command which automatically creates binary Debian packages (.deb) from Cargo projects.

Installation

rustup update   # Debian's Rust is too outdated, use rustup.rs
cargo install cargo-deb

Requires Rust 1.71+, and optionally dpkg, dpkg-dev and liblzma-dev. Compatible with Ubuntu. If the LZMA dependency causes you headaches, try cargo install cargo-deb --no-default-features.

If you get a compilation error, run rustup update! If you get an error running rustup update, uninstall your rust/cargo package, and install the official Rust instead.

Usage

cargo deb

Upon running cargo deb from the base directory of your Rust project, the Debian package will be created in target/debian/<project_name>_<version>-1_<arch>.deb (or you can change the location with the --output option). This package can be installed with dpkg -i target/debian/*.deb.

cargo deb --install builds and installs the project system-wide.

Configuration

No configuration is necessary to make a basic package from a Cargo project with a binary. This command obtains basic information it needs from the Cargo.toml file. It uses Cargo fields: name, version, license, license-file, description, readme, homepage, and repository.

For a more complete Debian package, you may also define a new table, [package.metadata.deb] that contains maintainer, copyright, license-file, changelog, depends, conflicts, breaks, replaces, provides, extended-description/extended-description-file, section, priority, and assets.

For a Debian package that includes one or more systemd unit files you may also wish to define a new (inline) table, [package.metadata.deb.systemd-units], so that the unit files are automatically added as assets and the units are properly installed. Systemd integration

Debug symbols

Debug symbols are stripped from built binaries by default, unless [profile.release] debug = true is set in Cargo.toml. If cargo deb --separate-debug-symbols is run, the debug symbols will be packaged as a separate file installed at /usr/lib/debug/<build-id-or-path>.debug. This can also be enabled via [package.metadata.deb] under separate-debug-symbols.

[package.metadata.deb] options

Everything is optional:

Example of custom Cargo.toml additions

[package.metadata.deb]
maintainer = "Michael Aaron Murphy <mmstickman@gmail.com>"
copyright = "2017, Michael Aaron Murphy <mmstickman@gmail.com>"
license-file = ["LICENSE", "4"]
extended-description = """\
A simple subcommand for the Cargo package manager for \
building Debian packages from Rust projects."""
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
    ["target/release/cargo-deb", "usr/bin/", "755"],
    ["README.md", "usr/share/doc/cargo-deb/README", "644"],
]

Advanced usage

Debian packages can use a number of different compression formats, but the target system may only support some of them. The default format is currently xz, but this may change at any point to support newer formats. The format can be explicitly specified using the --compress-type command-line option. The supported formats are "gzip" and "xz".

--fast flag uses lighter compression. Useful for very large packages or quick deployment.

--compress-system forces the use of system command-line tools for data compression.

[package.metadata.deb.variants.$name]

There can be multiple variants of the metadata in one Cargo.toml file. --variant=name selects the variant to use. Options set in a variant override [package.metadata.deb] options. It automatically adjusts the package name.

Merging Assets

When defining a variant it can be useful to also define different assets. If the merge-assets option is used, cargo-deb will merge the list of assets provided to the option with the parent asset list. There are three merging strategies, append, by.dest, and by.src.

Note: Using both append, and a by.* option are allowed, w/ the former being applied before the latter.

Example of merge-assets

# Example parent asset list
[package.metadata.deb]
assets = [
    # binary
    ["target/release/example", "usr/bin/", "755"],
    # assets
    ["assets/*", "var/lib/example", "644"],
    ["target/release/assets/*", "var/lib/example", "644"],
    ["3.txt", "var/lib/example/3.txt", "644"],
    ["3.txt", "var/lib/example/merged.txt", "644"],
]

# Example merging by appending asset list
[package.metadata.deb.variants.mergeappend]
merge-assets.append = [
    ["4.txt", "var/lib/example/appended/4.txt", "644"]
]

# Example merging by `dest` path
[package.metadata.deb.variants.mergedest]
merge-assets.by.dest = [
    ["4.txt", "var/lib/example/merged.txt", "644"]
]

# Example merging by `src` path
[package.metadata.deb.variants.mergesrc]
merge-assets.by.src = [
    ["3.txt", "var/lib/example/merged-2.txt", "644"]
]

# Example merging by appending and by `src` path
[package.metadata.deb.variants.mergeappendandsrc]
merge-assets.append = [
    ["4.txt", "var/lib/example/appended/4.txt", "644"]
]
merge-assets.by.src = [
    ["3.txt", "var/lib/example/merged-2.txt", "644"]
]

[package.metadata.deb.systemd-units]

See systemd integration.

Cross-compilation

cargo deb supports cross-compilation. It can be run from any unix-like host, including macOS, provided that the build environment is set up for cross-compilation:

Yes, these requirements are onerous. You can also try cross or cargo zigbuild, since Zig is way better at cross-compiling, and then run cargo deb --target=… --no-build.

cargo deb --target=i686-unknown-linux-gnu

Cross-compiled archives are saved in target/<target triple>/debian/*.deb. The actual archive path is printed on success.

Note that you can't use cross-compilation to build for an older version of Debian. If you need to support Debian releases older than the host, consider using a container or a VM, or make a completely static binary for MUSL instead.

Separate debug info

To get debug symbols, set in Cargo.toml:

[profile.release]
debug = true
# or debug="line-tables-only" for smaller files

Note: building using the dev profile is intentionally unsupported.

cargo deb --separate-debug-symbols --compress-debug-symbols

Removes debug symbols from the executables, and places them in separate files in /usr/lib/debug/.build-id/*. Requires GNU objcopy tool. --compress-debug-symbols uses zstd, and requires objcopy to support it.

Custom build flags

If you would like to handle the build process yourself, you can use cargo deb --no-build so that the cargo-deb command will not attempt to rebuild your project.

cargo deb -- <cargo build flags>

Flags after -- are passed to cargo build, so you can use options such as -Z, --frozen, and --locked. Please use that only for features that cargo-deb doesn't support natively.

Workspaces

Cargo-deb understands workspaces and can build all crates in the workspace if necessary. However, you must choose one crate to be the source of the package metadata. You can select which crate to build with -p crate_name or --manifest-path=<path/to/Cargo.toml>.

Custom version strings

cargo deb --deb-version my-custom-version

Overrides the version string generated from the Cargo manifest. It also suppresses the revision option.

Troubleshooting

For maximum logging, use:

RUST_LOG=debug cargo deb --verbose

Undefined reference to lzma_stream_encoder_mt error

This happens when the system-provided LZMA library is too old. Try with a bundled version:

cargo install cargo-deb --features=static-lzma

or use the xz command-line tool by setting the --compress-system flag.

[!NOTE] cargo-deb uses the xz2 crate that bundles an old safe version of liblzma 5.2 by the original maintainer, and a simple Cargo-based build script. It is unaffected by the CVE-2024-3094.