git clone https://git.pika-os.com/general-packages/pika-pkg-template foo
cd foo
main.sh: Generates deb files for standard debian packaging struture via dpkg-buildpackage.gitea workflows.debian dir: containing a very simple template of standard debian packaging structure.All of what the PikaOS package build workflow wants, is finding .deb files inside ./output after executing ./main.sh
This is the official by the book method, that generates build files that would be accepted not only by PikaOS gitea workflow, but also any other standard debian builder (such as buildd, or launchpad)
This Also offers other banefits such as:
This file tells APT and dpkg what your package is, what it needs, and how it relates to other packages.
A typical control file has two sections:
1. Source stanza
2. Binary package stanza(s)
Source: foo
Section: utils
Priority: optional
Maintainer: Your Name <you@example.com>
Build-Depends:
debhelper-compat (= 13),
cmake,
libfoo-dev
Standards-Version: 4.6.2
Rules-Requires-Root: no
Field-by-field
Source
Section
Priority
Maintainer
Build-Depends
Example:
Build-Depends: cmake, pkg-config, libgtk-3-dev
Standards-Version
Rules-Requires-Root
Each binary package gets its own stanza.
Package: foobar
Architecture: amd64
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: My cool app
A longer description that can span
multiple lines and explains what
the package actually does.
Package
Architecture
Depends
Depends:
${shlibs:Depends},
${misc:Depends}
You can add manual deps:
Depends:
${shlibs:Depends},
random-package,
libfoobar (= ${binary:Version})
Description
⸻
This file does three critical things:
1. Defines the package version
2. Controls rebuilds (Not in the PikaOS workflow though)
3. Records history
Example:
foo (1.2.0-101pika1) pika; urgency=medium
* Initial release
* Added cool feature
-- Your Name <you@example.com> Sat, 03 Feb 2026 12:00:00 +0000
Put the upstream/source name here
format: upstream-version-pikaos-revision
Example:
This is literally a Makefile.
Modern minimal rules file:
#!/usr/bin/make -f
%:
dh $@
This will make debhelper automatically attempt to configure, build, and install to the package virtual root, but many packages require customization.
That single line expands into dozens of steps:
During the build, nothing installs to /usr directly.
Instead, each package gets a fake root directory:
debian/<package-name>/
Example:
debian/foobar/usr/bin/my-app
debian/foobar/usr/share/my-package/data.json
This directory represents:
/
inside the final .deb
When the package installs:
debian/foobar/usr/bin/my-app → /usr/bin/my-app
This is why it’s called the package virtual root.
An override replaces or extends a debhelper step.
General form:
override_dh_<command>:
commands here
Debhelper will:
Default behavior:
dh_autoconfigure
Usually runs:
Override example:
override_dh_autoconfigure:
dh_autoconfigure -- \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_WAYLAND=ON
Why override it?
You’re still using dh_autoconfigure, just controlling it.
This is one of the most powerful overrides.
Default behavior
dh_install
It:
debian/<package>/override_dh_install:
dh_install
mkdir -p debian/my-package/etc/my-package
cp extra.conf debian/my-package/etc/my-package/
This is completely valid and very common.
You’re:
1. Letting debhelper do the normal install
2. Then manually adjusting the package root
Everything you touch must go under:
debian/<package-name>/
These files tell dh_install what goes where.
debian/my-package.install
usr
Runtime package
debian/libfoo1.install
usr
Development package
debian/libfoo-dev.install
usr/include/foo/*.h
usr/lib/$(DEB_HOST_MULTIARCH)/libfoo.so
usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig/foo.pc
Note: $(DEB_HOST_MULTIARCH) in rules and install files will be replaced by debhelper with the target arch (x86_64-linux-gnu)
Why split?
Control file must match
Package: libfoo1
Description: Foo runtime library
Package: libfoo-dev
Depends: libfoo1 (= ${binary:Version})
Description: Foo development files
These are shell scripts placed in debian/.
They run on the user’s system, not during build.
Runs after install or upgrade
Common uses:
Example:
#!/bin/sh
set -e
systemctl daemon-reload || true
systemctl enable my-service || true
Runs before removal or upgrade
Used for:
#!/bin/sh
set -e
systemctl stop my-service || true
Runs after removal
Used for:
#!/bin/sh
set -e
if [ "$1" = "purge" ]; then
rm -rf /etc/my-package
fi
Runs before install or upgrade
This will only be accepted if absolutely necessary, and the debs must have proper versioning meta data, and proper filenames when moved to ./output