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 for dependency resolution. The file consists of metadata comments, scalar variables, array variables, and hook functions.

File Layout

#!/bin/mkpkg
# *** krypt/sh ***
# 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: zorz.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. uses these for dependency resolution. makedeps are only needed during build and can be auto-removed.
depends=(openssl curl)
makedeps=(cmake ninja)

lockbox

Activate lockbox mode for this port. When set to yes, the build is run under the Linux Landlock LSM, restricting filesystem access to files owned by declared depends and makedeps packages plus a fixed implicit toolchain set. Any undeclared library or header is invisible to the build — configure, cmake, and the linker cannot find it. This enforces correct dependency declarations: if a library is not listed in depends or makedeps it cannot be silently linked.
lockbox=(yes)
Can be overridden on the command line with --no-lockbox or forced with --lockbox . Requires Linux 5.13+ with CONFIG_SECURITY_LANDLOCK=y .

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

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 addpkg(8) before file extraction and reversed by delpkg(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 delpkg(8), the user and group are removed if no other installed package declares the same group.

services

Declarative runit service enablement. On addpkg(8), a symlink is created: /service/name → /etc/sv/name On delpkg(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 addpkg(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 addpkg(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 krypt/sh-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 addpkg(8) and delpkg(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: zorz.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
# *** krypt/sh ***
# 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: zorz.pub
RWQ8...base64...==
}

# vim: filetype=sh
Package with privilege separation:
#!/bin/mkpkg
# *** krypt/sh ***
# 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

LLVM musl libc libressl Independent