β My First APKBUILD
β’ 1192 words β’ 6 min β’ updated
In the same spirit of my first PKGBUILD and Ebuild, herein I will describe my first APKBUILD.
At a glance #
Alpine Linux package management is very similar to Arch Linux, with tiny differences:
PKGBUILDβAPKBUILD: The filename is obviously different. Their format are very similar though, both of them are bash scripts with variables and functions. In particular, there’scheck,patch,buildandpackage.cp /usr/share/pacman/PKGBUILD.protoβnewapkbuild: Template versus scaffolding.pacmanβapk: The package manager is different.makepkg -sβabuild -r:makepkgdrives all things package building forpacman.abuilddrives package building forapk.makepkg -iβapk add <pkg>:makepkgcan also drive package installations whereasabuildcannot,apkmust be used.namcapβapkbuild-lint(fromatools) +abuild sanitycheck1: Linters are different.updpkgsumsβabuild checksum: Generate hashes for package sources.

XKCD Courtesy of Randall Munroe
Other than that, the process of writing an APKBUILD is very similar to writing a PKGBUILD. In fact, the Arch repositories (especially the AUR) tend to be much more comprehensive than Alpine’s in terms of number of packages, so chances are if you want to write a new package for Alpine, check in Arch’s repos first, it’s a good starting point.
My first package: fpp
#
fpp stands for ‘Facebook Path Picker’.
As of the time of this post, I maintain fpp-git in the AUR. It looks like this:
pkgname=fpp-git
pkgver=0.9.2.r130.ge0d5cfc
pkgrel=1
pkgdesc='TUI that lets you pick paths out of its stdin and run arbitrary commands on them'
url='https://facebook.github.io/PathPicker'
license=('MIT')
source=("${pkgname%-git}::git+https://github.com/facebook/PathPicker.git")
sha256sums=('SKIP')
arch=('any')
makedepends=('git')
depends=('python')
conflicts=("${pkgname%-git}")
provides=("${pkgname%-git}")
prepare() {
cd "$srcdir/${pkgname%-git}"
rm -r "src/tests"
}
pkgver() {
cd "$srcdir/${pkgname%-git}"
git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
}
package() {
cd "$srcdir/${pkgname%-git}"
# library
install -Dm755 "fpp" -t "$pkgdir/usr/share/fpp"
cp -a src "$pkgdir/usr/share/fpp"
# entrypoint
install -dm755 "$pkgdir/usr/bin"
ln -s "/usr/share/fpp/fpp" "$pkgdir/usr/bin"
# documentation
install -Dm644 LICENSE -t "$pkgdir/usr/share/licenses/$pkgname"
install -Dm644 "debian/usr/share/man/man1/fpp.1" -t "$pkgdir/usr/share/man/man1"
}PKGBUILD guidelines and instructions:
The equivalent APKBUILD I wrote looks like this:
pkgname=fpp
pkgver=0.9.2
pkgrel=0
pkgdesc="TUI that lets you pick paths out of its stdin and run arbitrary commands on them"
url="https://facebook.github.io/PathPicker"
arch="noarch"
license="MIT"
depends="bash python3"
subpackages="$pkgname-doc"
source="$pkgname-$pkgver.tar.gz::https://github.com/facebook/PathPicker/archive/$pkgver.tar.gz"
builddir="$srcdir/PathPicker-$pkgver"
check() {
fpp --version
}
prepare() {
default_prepare
rm -r "src/__tests__"
}
package() {
# library
install -Dm755 "fpp" -t "$pkgdir/usr/share/fpp"
cp -a src "$pkgdir/usr/share/fpp"
# entrypoint
install -dm755 "$pkgdir/usr/bin"
ln -s "/usr/share/fpp/fpp" "$pkgdir/usr/bin"
# documentation
install -Dm644 LICENSE -t "$pkgdir/usr/share/licenses/$pkgname"
install -Dm644 "debian/usr/share/man/man1/fpp.1" -t "$pkgdir/usr/share/man/man1"
}
sha512sums="
65b6b077f437bd642ebf94c55be901aabc73f7b9c89e4522c4f51970c4d63d744ad8fa29cac06816851f63bcb81d0480e61d405231c582e9aca0f4e650949a97 fpp-0.9.2.tar.gz
"APKBUILD guidelines and instructions:
- https://wiki.alpinelinux.org/wiki/Creating_an_Alpine_package
- https://wiki.alpinelinux.org/wiki/APKBUILD_Reference
Build Comparison #
Let’s highlight a few similarities and differences in them, excluding the fact that one is fetched from git and the other one fetches a point release directly2:
- package metadata, by the means of bash variables, are almost equivalent
one-to-one
β A notable difference is the architecture, Arch primarily supports
x86_64 whereas Alpine has support for multiple architectures. When
a package is architecture agnostic, Arch denotes it with
anywhereas alpine has bothnoarchandall, the latter is likeany(=all architectures), theformermeans it’s agnostic (=e.g. a pure bash script or python package). βAPKBUILDsuse flat strings, whereasPKGBUILDsuse bash arrays β Alpine encourages splitting larger packages into subpackages, as suchAPKBUILDhas first-class support and syntactic sugar for that.-devand-docsubpackages are very common. On the other hand, Arch tends to have monolithic packages in order to keep it simple, although it also supports subpackages. β Alpine supports setting$builddirwhereas Arch doesn’t. As a consequence, it’s often unneeded tocdinbuild()andpackage()in Alpine, whereas in Arch one does need to manually change directories to$srcdir/$pkgnamebefore building. β Alpine lacks optional dependencies, whereas Arch hasoptdepends. - Alpine enforces the use of
checkin test packages, otherwise it needs to be explicitly disabled and documented with!checkinoptions=. That’s not the case in Arch. check(),build()andpackage()are pretty much similar in both formats.$srcdirand$pkgdirare provided in both.- The ArchWiki is way more documented in terms of packaging guidelines and examples than Alpine’s. If you use DuckDuckGo, you can query for
!aw <foo>as a bang shortcut to search directly in the ArchWiki.
Last but not least, in Arch one can install package tarballs3 with makepkg -i or pacman -U. In Alpine that approach doesn’t seem to be directly supported. The workflow is to add a local repository directory in /etc/apk/repositories (notice the last two lines):
# http://dl-cdn.alpinelinux.org/alpine/v3.15/main
# http://dl-cdn.alpinelinux.org/alpine/v3.15/community
# http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
# http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
http://dl-cdn.alpinelinux.org/alpine/edge/main
http://dl-cdn.alpinelinux.org/alpine/edge/community
http://dl-cdn.alpinelinux.org/alpine/edge/testing
/home/$USER/packages/community
/home/$USER/packages/testingabuild will place the resulting package tarball in ~/packages, in this case:
$ ls ~/packages/testing/x86_64/fpp*
/home/$USER/packages/testing/x86_64/fpp-0.9.2-r0.apk
/home/$USER/packages/testing/x86_64/fpp-doc-0.9.2-r0.apk…and then apk add fpp will automagically recognize it’s in there and install it. The advantage of this approach is that it keeps a local package repository around and it’s well integrated with apk, way differently from pacman that has no integration with the AUR at all. One could also possibly set up a local repository in Arch, for example, with ccm, but it takes extra steps and it’s not officially supported.
Upstream Contributions #
On Arch, to contribute a PKGBUILD upstream one just needs to create an account in the AUR. Armed with a git + ssh infrastructure, all you need to do is git push. There are no ACLs involved, anyone can do that4.
On Alpine there’s a bit more of politics involved5: Anyone can send a patch(1), either via mailing list or via a Gitlab MR (merge request). Patch works well with git send-email -1, being automatically cross-posted to a Gitlab MR. On the other hand the MR workflow is easier to be followed up on feedback from developers and other contributors (git push --force), and it’s also cross-posted, to the mailing list. An Alpine developer with the appropriate permissions must approve your patch/MR before it becomes available to other Alpine users.
Sadly at the time of this writing my patch hasn’t yet been approved (2 weeks later), however we’re in holiday season. This wouldn’t have been a problem in the AUR, where I could have just pushed it immediately, without any review. On the other hand the Alpine approach at least gives me some hope that the submitted packages have slightly higher quality than the average ones in the AUR, since they need to be manually reviewed/approved/vetted by at least one Alpine developer.
-
Install
spdx-licenses-listto lint the licenses, it’s used byabuild sanitycheckas an optional dependency. ↩︎ -
The AUR tends to have both non-vcs and vcs versions of a software, whereas Alpine is focused a bit more on stability and tends to have non-vcs only. This is not a hard rule though, exceptions may exist. ↩︎
-
.tar.xzor, more recently,.tar.zstd. ↩︎ -
And this is one of the reasons why you should always inspect every
PKGBUILDyou install from the Arch User Repository, as it could have been tampered with and/or contain malicious code. ↩︎ -
I’ll leave it open-ended whether that’s a bug or a feature. Depending on the lens you see through, it could be considered either gatekeeping (bureaucracy, control) or sanity (quality, stability). It has pros and cons, and even those are arguable. ↩︎
Backlinks
- Alpine Linux: New APKBUILD Workflow (Jan 23, 2022)