Quick reference to build a Debian/Ubuntu package with debmagic.
- Entry point:
debmagic build binary— build on anydebian/-packaged source tree (including packages withdebian/rules.py) - Source package:
debmagic build source, creates a.dscwithout compilation
cd your-package
debmagic build binary --driver lxd \
--output-dir /tmp/build-artifactsdebmagic build:
| Option | Description |
|---|---|
--driver <...> |
Build environment driver to use |
--source-sync <mode> |
Which source files to include |
--persistent |
Retain the build environment. This does not do incremental builds. |
--incremental |
Do incremental builds by syncing changed sources only; implies persistent |
--distro <name> |
Select the target distro/release (e.g. trixie, resolute) |
--proposed |
Use build dependencies from proposed pocket |
--sign |
GPG-sign the resulting .changes/.dsc/.buildinfo |
--clean |
Run debian/rules clean before building |
--debug-symbols |
Build the automatic -dbgsym debug symbol packages |
--apt-mirror <url> |
Mirror URL |
--source-dir <dir> |
Directory containing the debian/ package directory |
--output-dir <dir> |
Directory to put the resulting build artifacts |
--shell-on-failure |
On build failure, drop into an interactive shell in the build environment when stdout is a TTY |
debmagic shell — attach an interactive shell to a build environment
Check what's installed and use the first that applies, in this order:
| Driver | Check it's available | Isolation |
|---|---|---|
lxd / incus |
lxc list / incus list |
Full container isolation |
docker |
docker info |
Full container isolation |
bare |
none (no daemon) | None — build-deps install with sudo apt-get directly on the host; only use in a disposable/CI environment |
There's no auto-detection; pick one and pass it explicitly every time (or configure it in a debmagic.toml file).
On failure the build environment is torn down by default. Pass --shell-on-failure to drop into an interactive shell inside the build environment when stdout is a TTY (destroyed on shell exit unless --persistent was used).
To inspect after the run finishes, pass --persistent up front, then:
# if you're in the package still
debmagic shell
# from the outside:
debmagic shell --source-dir /path/to/parent/of/debian/dirThis attaches an interactive shell inside the still-running (or restartable) build environment, at the package's build directory.
Fresh containers install their base tooling plus every Build-Depends, so slow mirrors directly translate into slow builds.
Pass --apt-mirror to use a faster mirror for build-dependency resolution after the base tooling is bootstrapped from the image's configured archives:
debmagic build binary --driver lxd --apt-mirror http://<mirror-host>/ubuntu ...You can persistently set this flag in .config/debmagic/config.toml.
Before building, debmagic stages the source tree into the build environment.
--source-sync <mode> controls which files are staged, so you always know what ends up in the build and in a generated source package:
| Mode | Stages | Notes |
|---|---|---|
tracked (default) |
git-tracked files, including uncommitted modifications | Untracked files are left out and listed as a warning — git add them or switch modes to include them |
committed |
the same files as tracked |
Fails if the worktree has uncommitted changes or untracked files; use for reproducible, reviewable source packages |
worktree |
everything that isn't git-ignored, tracked or not |
If the source directory is not a git worktree, tracked and committed fall back to worktree with a warning.
Git submodules are skipped with a note, since their contents aren't tracked by the parent repository.
To persist a mode, set source_sync_mode = "committed" in debmagic.toml.
You can iterate on the same build for faster compile times.
Every debmagic build binary invocation creates a new container by default and tears it down afterwards.
For repeated attempts against the same package and distro, add --persistent to retain and reuse the running environment while restaging the source tree for each build:
debmagic build binary --driver lxd --persistent \
--source-dir . --output-dir /tmp/outUse --incremental to retain the environment and synchronize only source changes while preserving generated files and unchanged source inodes.
This flag implies --persistent, and cannot be combined with --clean yes.
The preserved build tree is kept even when the environment itself is not reused (e.g. a fresh CI runner where the tree was restored from a cache).
Only needed when debian/changelog's top entry doesn't unambiguously determine the target: pass --distro <codename> (e.g. --distro noble, --distro trixie).
If the changelog has a single unambiguous entry, omit it.
Suite aliases in the changelog (or via --distro) resolve to a concrete release: Debian stable / oldstable / sid (→ unstable), and Ubuntu devel.
Alias targets are updated manually when Debian/Ubuntu roll.
Non-Debian/Ubuntu suites (still apt/dpkg-based) are supported when declared for the active container Driver via base_images, e.g. driver.docker.base_images = { "yocto:kirkstone" = "my-registry/yocto-kirkstone:latest" }. The changelog/--distro value stays the bare codename (kirkstone). On the Bare driver, the host /etc/os-release must match: built-in Debian/Ubuntu need matching ID and codename; other suites need a matching VERSION_CODENAME only.
If needed, build dependencies can be used from <release>-proposed.
Pass --proposed to enable the proposed pocket in the build environment.
By default debmagic build binary passes DEB_BUILD_OPTIONS=noautodbgsym to dpkg-buildpackage, which suppresses debhelper's automatic -dbgsym package (the detached debug info package debhelper otherwise builds by default from compat 9 onward).
Pass --debug-symbols to build it for one invocation:
debmagic build binary --debug-symbols --output-dir /tmp/outOr set build_debug_symbols = true in the debmagic.toml.
--sign GPG-signs the resulting .changes/.dsc/.buildinfo after building — mainly useful for source builds destined for Launchpad, but works for binary builds too.
Signing is debmagic's own reimplementation of debsign and always runs on the host with your gpg keyring: the artifacts are exported to the host output dir first, so no container or agent forwarding is involved.
Children are signed first (.dsc, then .buildinfo) and the .changes checksums are rewritten after each, exactly like debsign.
| Option | Config | Description |
|---|---|---|
--sign |
sign.source |
Sign after building; --sign=false skips it for one invocation |
--sign-key <key> |
sign.key |
Key ID/fingerprint/email; defaults to the Changed-By:/Maintainer: address of the file being signed |
--sign-tool <tool> |
sign.tool |
OpenPGP implementation: gpg (default), sequoia (sq), or custom |
--sign-command <cmd> |
sign.command |
Custom signing command for --sign-tool custom (see below) |
--sign-notify |
sign.notify |
Desktop notification + terminal bell just before signing, so a hardware-key touch prompt isn't missed after a long build |
A custom signing command runs without a shell and must write the clearsigned result to stdout.
The file to sign is passed via the {file} placeholder (or, if no placeholder is used, as the last argument).
| Placeholder | Expands to |
|---|---|
{file} |
Path of the file to sign |
{key} |
The resolved signing key |
{email} |
The bare address of the key |
Unknown placeholders are an error.
Defaults can be set in debmagic.toml.
debmagic sign signs a .changes file (and its .dsc/.buildinfo children) that already exists — the same code path --sign uses after a build:
debmagic sign ../mypkg_1.0_amd64.changesWithout a file argument, it locates the .changes via debian/changelog and --output/-o (default: the output_dir config, build/ under the package root), preferring the source-only _source.changes when several match.
--clean runs debian/rules clean before building, like plain dpkg-buildpackage does unless passed -nc; --clean=false skips it even if the config file defaults to cleaning.
Non-incremental builds already stage a clean source tree, while incremental builds preserve outputs intentionally.
Enable cleaning only for packages whose clean target performs required setup or code generation.
Instead of repeating CLI flags on every invocation, drop a config file.
- Container/device names are derived and sanitized internally (alphanumeric + hyphen, ≤63 chars for LXD/Incus) — don't try to predict or construct them yourself; use
debmagic shellinstead oflxc/dockercommands directly.