MAKEPKG

package build recipe for mkpkg

Synopsis

/ports/*/\:/MAKEPKG

Description

A MAKEPKG file is a shell-like recipe that describes how to fetch, build, and package a piece of software. It is read by mkpkg(8) and parsed by tux(8) for dependency resolution. The file consists of metadata comments, scalar variables, array variables, and hook functions.

File Layout

#!/bin/mkpkg
# description: one-line summary
# url: upstream homepage

name=example
version=1.0
release=1
depends=(foo bar)
makedeps=(baz)
source=(https://example.com/$name-$version.tar.gz)
sha256sums=(abc123...)

build() {
cd $name-$version
./configure --prefix=/
make
make DESTDIR=$PKG install
}

signify() {
untrusted comment: opentux.pub
RWQ8ABCD1234...base64...==
}

# vim: filetype=sh

Scalar Variables

name
Package name (required).
version
Package version (required).
release
Package release number (required). Increment when the MAKEPKG changes but the upstream version does not.
Custom variables are also supported and exported to all hooks:
_branch=stable
_commit=abc1234

Array Variables

Arrays use shell-style parenthesized syntax. Multi-line arrays are supported.

depends, makedeps

Runtime and build-time dependencies. tux(8) uses these for dependency resolution. makedeps are only needed during build and can be auto-removed.
depends=(openssl curl)
makedeps=(cmake ninja)

source

Source URLs or local filenames. Variables $name, $version, and custom variables are expanded.
source=(https://example.com/$name-$version.tar.gz
fix-build.patch)
Local files (no path separator) are looked up relative to the port directory.

renames

Rename downloaded files. Positional — entry

N

in renames applies to entry

N

in source. Use empty strings or SKIP to leave entries unchanged.
source=(https://example.com/archive/v$version.tar.gz)
renames=($name-$version.tar.gz)

sha256sums, b2sums

Checksums for each source entry. Generate with mkpkg -x . Update in-place with mkpkg -ux . Use SKIP for entries that should not be verified.
sha256sums=(a1b2c3d4...
SKIP)

groups

Declarative system group and user creation. Processed by pkg.add(8) before file extraction and reversed by pkg.del(8) on removal. Simple format — create a system group:
groups=(groupname)
Extended format — create a group, system user, and home directory:
groups=(groupname:user:username:homedir:mode)
The second field must be the literal word user . Example:
groups=(dhcpcd:user:dhcpcd:/var/lib/dhcpcd:700)
This runs:
groupadd -r dhcpcd
useradd -r -s /bin/false -d /var/lib/dhcpcd -g dhcpcd dhcpcd
install -d -m 700 -o dhcpcd -g dhcpcd /var/lib/dhcpcd
On pkg.del(8), the user and group are removed if no other installed package declares the same group.

services

Declarative runit service enablement. On pkg.add(8), a symlink is created: /service/name → /etc/sv/name On pkg.del(8), the symlink is removed. The service directory under

/etc/sv

is a regular package file shipped by build() or post_build() .
services=(nftables)

permissions

Declarative file ownership and mode adjustments. Applied by pkg.add(8) after extraction. Format:
/path:owner:group:mode
Example:
permissions=(
/sbin/wpa_supplicant:root:wpa_supplicant:750
/sbin/wpa_cli:root:wpa_supplicant:750
/etc/wpa_supplicant.conf:root:wpa_supplicant:640
)
Paths are relative to the installation root. No undo is needed on removal — the files are deleted.

capabilities

Declarative file capability adjustments. Applied by pkg.add(8) after extraction, using setcap (8) from libcap . Format:
/path:capabilities
Example:
capabilities=(
/usr/bin/ping:cap_net_raw+ep
/usr/bin/arping:cap_net_raw+ep
)
Capabilities are extended attributes and cannot survive in tar archives, which is why they are applied at install time rather than at build time. Paths are relative to the installation root. No undo is needed on removal — the files are deleted.

Hook Functions

Hooks are shell functions executed during the build pipeline. Each receives the environment described in mkpkg(8).

shell()

Runs

twice

if defined twice. The first shell() runs before download (setup phase); the second runs after packaging (cleanup phase). Both execute in the port directory. Typical use: create temporary wrapper scripts for builds that need them, then remove them afterward.
shell() {
ln -sf /bin/python3 $SRC/.local/bin/python
}
Both invocations source /etc/mkpkg.conf .

extract()

Custom extraction. Runs in the port directory (PKGMK_SOURCE_DIR). When defined, mkpkg skips auto-extraction of source archives. Does

not

source mkpkg.conf.
extract() {
tar -xf $PKGMK_SOURCE_DIR/$name-$version.tar.gz -C $SRC
}

patch()

Apply patches after extraction. Runs in $SRC. Does

not

source mkpkg.conf.
patch() {
cd $name-$version
patch -p1 < $PKGMK_SOURCE_DIR/fix-musl.patch
}

build()

Main build function (required). Runs in $SRC. Sources mkpkg.conf.
build() {
cd $name-$version
./configure --prefix=/
make
make DESTDIR=$PKG install
}

post_build()

Post-build fixups. Runs in $SRC after build() . Sources mkpkg.conf. Use for OpenTUX-specific additions: runit service files, configuration files, cleanup of unwanted files.
post_build() {
cd $name-$version

install -d $PKG/etc/sv/$name/log

printf '%s\\n' \\
'#!/bin/sh' \\
'exec 2>&1' \\
"exec $name -f" \\
> $PKG/etc/sv/$name/run

printf '%s\\n' \\
'#!/bin/sh' \\
"mkdir -p /var/log/$name" \\
"exec svlogd -tt /var/log/$name" \\
> $PKG/etc/sv/$name/log/run

chmod 755 $PKG/etc/sv/$name/run
chmod 755 $PKG/etc/sv/$name/log/run
}

Metadata File

When groups, services, permissions, or capabilities arrays are defined, mkpkg writes a metadata file into the package at: var/lib/pkg/meta/name Format:
group dhcpcd:user:dhcpcd:/var/lib/dhcpcd:700
service dhcpcd
permission /sbin/dhcpcd:root:dhcpcd:750
capability /usr/bin/ping:cap_net_raw+ep
This file is read by pkg.add(8) and pkg.del(8) and is tracked as a regular package file.

Signify Function

signify()

Embeds the signify public key for this port directly in the MAKEPKG. This is

not

a shell function — it is a data block containing two lines: the untrusted comment and the base64-encoded public key.
signify() {
untrusted comment: opentux.pub
RWQ8ABCD1234...base64...==
}
When verifying a port signature, mkpkg uses this embedded key instead of looking for external

.pub

files in /etc/ports/ . This makes each port self-verifying: the trust is per-port and transparent. Generate or update with:
mkpkg -up        # reads .pub matching MKPKG_SECRET_KEY
Display with:
mkpkg -p         # prints the embedded key
The signify() block should be placed at the end of the file, just before the # vim: footer.

Examples

Minimal package:
#!/bin/mkpkg
# description: Shows the full path of shell commands
# url: https://www.gnu.org/software/which/

name=which
version=2.21
release=1
depends=()
source=(https://ftp.gnu.org/gnu/$name/$name-$version.tar.gz)

build() {
cd $name-$version
./configure --prefix=/
make
make DESTDIR=$PKG install
}

signify() {
untrusted comment: opentux.pub
RWQ8...base64...==
}

# vim: filetype=sh
Package with privilege separation:
#!/bin/mkpkg
# description: DHCP client daemon
# url: https://github.com/NetworkConfiguration/dhcpcd

name=dhcpcd
version=10.2.2
release=1
depends=(openssl)
groups=(dhcpcd:user:dhcpcd:/var/lib/dhcpcd:700)
services=(dhcpcd)
permissions=(
/sbin/dhcpcd:root:dhcpcd:750
)
source=(https://github.com/NetworkConfiguration/$name/releases/download/v$version/$name-$version.tar.xz)

build() {
cd $name-$version
./configure --prefix=/ --privsepuser=dhcpcd
make
make DESTDIR=$PKG install
}

post_build() {
cd $name-$version
install -d $PKG/etc/sv/$name/log
# ... service files ...
}

# vim: filetype=sh

See Also

Pure LLVM musl libc Source-Based Independent