Packaging

This page explains how to create packages in postmarketOS, so they can be built with the usual pmbootstrap build hello-world.
== General information ==
* Read the 
* Don't add # Contributor: lines in pmaports ()
* Don't copy maintainers from the other packages to packages you add (e.g. when temporarily forking them from Alpine).
* Use pmbootstrap lint to lint your package
* Alpine uses busybox' sh for building packages. Do not use bash specific features.
* If the software doesn't have a proper release yet, ask upstream to make a release.
== Generate a template ==
Create a template for a new package called mynewpackage in aports/main:
$ pmbootstrap newapkbuild mynewpackage
[21:34:27] Create /home/user/code/pmbootstrap/aports/main/mynewpackage
[21:34:27] Done
We pass the arguments to from Alpine, which has lots of parameters to quickly customize the templates it generates. It is even possible to just specify the URL and let it download the tarball and automatically recognize the build system, package name and version:
$ pmbootstrap newapkbuild "https://github.com/alpinelinux/abuild/archive/v3.1.0.tar.gz"
For reference, see the full help output:
$ pmbootstrap newapkbuild -h
Remember to update the checksums after changing the sources:
$ pmbootstrap checksum hello-world
== Packaging git commits ==
Only package git commits when necessary. Stable releases are preferred. Consider asking upstream to tag releases.
* pkgver: We use the following format: $lastrelease_gitYYYYMMDD, e.g. 1.0_git20171101 (that makes it easy to see how old the commit is and apk is able to upgrade the package properly when the next release, e.g. 1.1, comes out)
* Save the git commit in a variable _commit=.... and use it throughout the APKBUILD (e.g. in the builddir), so it's easy to update it.
* The source should be saved with the $_commit in the filename. For GitHub links, this means:
 source="$pkgname-$_commit.tar.gz::https://github.com/ORG/NAME/archive/$_commit.tar.gz"
== Subpackages ==
In some cases it's required to split up a package. For example if some files are not required unless specific software exists. With the subpackages= variable it's possible to define split functions that will run after the package() function to move specific files to
a subpackage. Abuild provides a few helper functions that automatically do some common split operations. Some of these are $pkgname-dev, $pkgname-doc, $pkgname-openrc and $pkgname-static. The abuild output will usually contain a warning telling you
to add these subpackages when those files are detected in the main package.
Sometimes you need to add custom subpackages, these can be defined with $pkgname-coolname:functionname. Here's an example:
# some variables skipped for smaller example
pkgname=hello-world
pkgver=1
arch="all"
subpackages="$pkgname-example:example"
source="main.c example.c Makefile"
build() {
	cd "$srcdir"
	make
}
package() {
	# The package will install /usr/bin/main and /usr/bin/example for this example
	make install DEST="$pkgdir"
}
example() {
	# This function is called after package() and will move files from the main package to the subpackage
	amove usr/share/example
	# The amove command is a utility that basically does this but with more error checking:
	mv $pkgdir/usr/share/example $subpkgdir/usr/share/example
}
It's not required that the files in the split functions are installed by package() first. It's possible to create split functions that create completely independent packages by taking files from $srcdir instead of $pkgdir
== OpenRC subpackages ==
Alpine Linux and postmarketOS packages that provide openrc related files should have an -openrc subpackage . To add such a package, just put $pkgname-openrc in subpackages. abuild will then use the default function to split the appropriate files into the subpackage, and to install the subpackage automatically if openrc is installed.
=== When to depend on -openrc subpackages ===
Since postmarketOS has added systemd, regular packages must not depend on -openrc subpackages.
It is fine for -openrc subpackages (or other packages that we install exclusively for openrc, such as -elogind subpkgs) to depend on other -openrc subpackages if it makes sense.
=== How to automatically enable OpenRC services ===
In systemd installs, we use systemd preset logic. With OpenRC we enable OpenRC services that have to be enabled by default for a functional system in post-install scripts.
Example for starting eg25-manager in device-pine64-pinephone:
openrc() {
	install_if="$pkgname=$pkgver-r$pkgrel openrc"
	install="$subpkgname.post-install $subpkgname.post-upgrade"
	depends="eg25-manager-openrc"
	mkdir "$subpkgdir"
}
$ cat device/community/device-pine64-pinephone/device-pine64-pinephone-openrc.post-install
#!/bin/sh
rc-update add eg25-manager default
exit 0
$ cat device/community/device-pine64-pinephone/device-pine64-pinephone-openrc.post-upgrade
#!/bin/sh
rc-update add eg25-manager default
rc-update -qq del gpsd
rc-update -qq del gpsd_pinephone
exit 0
== When should pkgver/pkgrel get increased? ==
Whenever you update a package, it must have a new version. A version consists of $pkgver-r$pkgrel. The says:
* pkgver: The version of the software being packaged.
* pkgrel: Alpine/postmarketOS package release number. Starts at 0 (zero). Always increment pkgrel when making updates to an aport; reset pkgrel to 0 (zero) when incrementing pkgver.
As a general rule, whenever a change is made to upstream sources, pkgver should be increased.
When packaging-related files (APKBUILD, any post-install scripts, patch files to upstream sources, etc) are changed, pkgrel should be increased.
=== device packages and other packages without sources === 
Packages without upstream sources are a bit special. These are device-* packages and other packages like main/postmarketos-base, where the source files are included in the package directory. For these packages, the packaged sources should be treated as upstream sources. In consequence, the pkgver should be increased when the checksums change. Any other change should bump pkgrel. 
It is also important to remark that for these packages the pkgver provides no meaning. The current policy is to have pkgver be an ever-increasing integer. See for the discussion related to this decision.
=== kernel packages ===
We always set the pkgver to the kernel version number and only increase it when the kernel source code has a new version number. All kernel config changes only increase the pkgrel number. In the case, that the linux kernel sources need to be updated, but the kernel version was not changed (Android kernel forks often do this), we can add a _gitYYYYMMDD suffix (see "Packaging git commits" above).
=== _pmb_recommends ===
Changes to the _pmb_recommends variable do not require bumping pkgver or pkgrel. The reason is that those are parsed directly by pmbootstrap from the APKBUILD file, and not extracted from the build package.
== Guidelines for packaging patches ==
* The release branches (v21.03 etc.) should be a snapshot of edge (master branch), therefore all patches that are desired on release branches need to be on edge too.
* The maintenance effort for patches must be reasonable.
* Patches must align with our principles.
** Having patches that make software align to our principles are desired, even if they cannot be upstreamed.
* Device specific patches/hacks should be contained in the device package, if possible. Or self-contained and affect only the patched package, if possible.
* Upstream patches (if they can be upstreamed) as we add them to pmaports. Link to where the patch is being upstreamed in the packaged patch.
* Each patch must have a meaningful description (explanation what it does and why it is needed).
== Should my package be in postmarketOS or Alpine? ==
You should submit to and maintain your package in Alpine's aports instead of postmarketOS if possible, so more people can use it.
Exceptions:
* packages that are needed for postmarketOS and will not get accepted in Alpine (example: waydroid-image)
* packages that override configs from alpine (usually these go in postmarketos-* packages)
* packages with postmarketOS branding (e.g. mobile-config-firefox mentions pmOS on the start page)
* packages with postmarketOS specific hooks (osk-sdl triggers initramfs rebuild)
* packages that define services to get enabled (usually in postmarketos-ui-* packages)
* cross compiler related / old gcc versions (everything in cross/, see )
* packages starting with: device-*, linux-*, firmware-*, soc-* (everything in device/)
* device specific forks of packages (e.g. u-boot)
* when upstreaming a package to alpine means it can't be moved out of aports/testing (e.g. crust depends on cross compiler pkg from testing)
* packages used in pmOS testsuites (main/hello-world*)
Note that packages are initially submitted to the "testing" dir of Alpine's aports, and as soon as they are built and tested, you are expected to make another merge request that moves the package to the "community" dir. This is also important for postmarketOS, because without having your package in "community", it will not become available in the stable releases of Alpine.
== Device specific quirks ==
Device specific quirks should be in device specific packages, if they only affect one device. If they affect more than one device:
* udev rules:
** since they only run on specific kernel modules, they are unlikely to cause problems with other devices that don't need them
** so as long as they don't cause problems with devices that don't need the quirk, put them in postmarketos-base
** this is consistent with how udev rules are done in general, by other packages (example)
** we decided for now that it's not worth the overhead of creating a separate (sub)package for these lighweight udev rules
* for other quirks: a subpackage (postmarketos-quirks-... or devicepkg-quirk-...? see )
** at time of writing, this is just a proposal
** create a quirks package, and one subpackage per quirk
** let other devices that need them depend on these quirks
** (nothing depends on the main quirks package)
== Outdated config.sub/config.guess from autotools ==
In case the config.sub or config.guess are outdated, change the APKBUILD's prepare block to the following:
prepare() {
	default_prepare
	update_config_sub
	update_config_guess
}
== Related ==
* How to create a patch when packaging software
* Installing packages on a running phone
Category:Guide