$linuxjunkies
>

Build an Arch AUR Package (PKGBUILD)

Learn to write an Arch Linux PKGBUILD from scratch, build it with makepkg, lint it with namcap, and publish it to the AUR step by step.

IntermediateUbuntuDebianFedoraArch10 min readUpdated June 7, 2026

Before you start

  • Arch Linux installation with internet access
  • base-devel package group installed
  • AUR account at aur.archlinux.org with SSH public key configured
  • Basic familiarity with Bash scripting and a build system such as CMake or Make

The AUR (Arch User Repository) is one of Arch Linux's greatest strengths. Instead of waiting for a maintainer to package software, you write a PKGBUILD — a plain Bash script that tells makepkg how to fetch, build, and package any software into a standard .pkg.tar.zst archive. This guide covers writing a real PKGBUILD from scratch, testing it with namcap, and submitting the result to the AUR.

Prerequisites and Setup

You need a working Arch Linux installation with the base-devel group installed. This group includes makepkg, gcc, make, binutils, and the other tools the build process depends on.

sudo pacman -S --needed base-devel git namcap

For AUR submission, register an account at aur.archlinux.org and add your SSH public key in your account settings. You interact with the AUR via a dedicated Git remote, not a web upload form.

PKGBUILD Anatomy

A PKGBUILD is a Bash script sourced by makepkg. Every variable and function below is either required or strongly recommended.

Header variables

# Maintainer: Your Name <[email protected]>
pkgname='myprog'
pkgver='1.4.2'
pkgrel=1
epoch=          # leave blank unless you need to force a downgrade
pkgdesc='A short, accurate one-line description (≤80 chars)'
arch=('x86_64' 'aarch64')
url='https://github.com/example/myprog'
license=('MIT')
depends=('glibc' 'zlib')
makedepends=('cmake')
optdepends=('python: for the helper scripts')
provides=()     # if this replaces another package name
conflicts=()    # packages that must not be installed alongside this one
source=("${pkgname}-${pkgver}.tar.gz::https://github.com/example/myprog/archive/v${pkgver}.tar.gz")
b2sums=('SKIP') # replace SKIP with a real checksum before publishing
  • pkgrel: Reset to 1 when pkgver changes; increment it for packaging-only fixes at the same upstream version.
  • arch: Use ('any') for architecture-independent packages (pure Python, shell scripts, fonts).
  • depends vs makedepends: depends are needed at runtime; makedepends are only needed to build and can be absent on the end-user's machine.
  • source: Each entry is a URL, optionally prefixed with localname:: to rename the downloaded file. Git sources use the form "git+https://...".

Checksum generation

Never leave SKIP in a published PKGBUILD. Generate real checksums after your source URLs are final:

makepkg -g

Copy the printed b2sums array into your PKGBUILD. b2sums (BLAKE2) is the current preference; sha256sums is also acceptable.

Build and package functions

prepare() {
  cd "${srcdir}/${pkgname}-${pkgver}"
  # Apply patches, run autoreconf, etc.
  patch -p1 < "${srcdir}/fix-build.patch"
}

build() {
  cd "${srcdir}/${pkgname}-${pkgver}"
  cmake -B build \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr
  cmake --build build
}

check() {
  cd "${srcdir}/${pkgname}-${pkgver}"
  cmake --build build --target test
}

package() {
  cd "${srcdir}/${pkgname}-${pkgver}"
  DESTDIR="${pkgdir}" cmake --install build
  install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}

Key rules:

  • prepare() and check() are optional but recommended when applicable.
  • Always install into ${pkgdir}, never into the live filesystem.
  • Use install -Dm755 for executables and -Dm644 for data/config files; this sets owner, permissions, and creates parent directories in one command.
  • License files must land in /usr/share/licenses/${pkgname}/.
  • Never hardcode paths. Use the $srcdir and $pkgdir variables makepkg provides.

VCS Packages (Git Sources)

For packages tracking a Git repository's HEAD, the convention is to append -git to pkgname and implement a pkgver() function that generates a version string dynamically:

pkgname='myprog-git'
pkgver='r142.abc1234'  # placeholder; pkgver() overwrites this at build time
source=("git+https://github.com/example/myprog.git")
b2sums=('SKIP')        # SKIP is acceptable for git+https sources

pkgver() {
  cd "${srcdir}/myprog"
  printf 'r%s.%s' "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}

makepkg calls pkgver() after cloning/fetching and updates the variable before packaging. The SKIP checksum is allowed for VCS sources because the commit hash provides integrity.

Building and Testing with makepkg

First build

cd ~/builds/myprog
makepkg -si

-s installs missing dependencies automatically via pacman; -i installs the built package when done. Output will vary; watch for errors in the build or check phases.

Iterating quickly

# Skip re-extracting sources after first run
makepkg -si --noextract

# Clean old build artifacts and rebuild from scratch
makepkg -si --clean

Inspect the package contents

pacman -Qlp myprog-1.4.2-1-x86_64.pkg.tar.zst

Verify binaries land in /usr/bin, libraries in /usr/lib, and that no files end up in /usr/local or other non-standard paths for packaged software.

Linting with namcap

namcap analyses both the PKGBUILD and the built package for common mistakes: missing dependencies, wrong permissions, hardcoded paths, and packaging policy violations.

# Lint the PKGBUILD itself
namcap PKGBUILD

# Lint the compiled package archive
namcap myprog-1.4.2-1-x86_64.pkg.tar.zst

Lines prefixed with E: are errors that must be fixed. Lines prefixed with W: are warnings worth reviewing. A clean package shows no output from either command. Fix every error before submitting to the AUR — reviewers and AUR helpers will run namcap themselves.

Submitting to the AUR

Create the remote repository

The AUR creates a new package repository the first time you push to it. The remote URL format is fixed:

git init
git remote add aur ssh://[email protected]/myprog.git

Generate .SRCINFO

The AUR web interface and AUR helpers parse .SRCINFO, a static metadata file derived from your PKGBUILD. Regenerate it every time you change the PKGBUILD:

makepkg --printsrcinfo > .SRCINFO

Commit and push

git add PKGBUILD .SRCINFO
git commit -m 'Initial release 1.4.2-1'
git push aur HEAD:master

The AUR server validates the push. If .SRCINFO is missing or malformed, the push is rejected with a descriptive error. After a successful push, your package appears at https://aur.archlinux.org/packages/myprog within seconds.

Updating an existing package

Clone your AUR repo first if you are on a new machine, then edit and push:

git clone ssh://[email protected]/myprog.git
cd myprog
# Edit PKGBUILD: bump pkgver, reset pkgrel to 1, update checksums
makepkg -g  # regenerate checksums
makepkg --printsrcinfo > .SRCINFO
git add PKGBUILD .SRCINFO
git commit -m 'Upstream 1.4.3'
git push

Troubleshooting

  • makepkg fails checksum verification: The upstream tarball changed. Re-run makepkg -g to update checksums, but verify the upstream release is legitimate before publishing the new hash.
  • namcap reports "dependency not found": The library is provided by a package with a different name. Use pkgfile /usr/lib/libfoo.so (requires pkgfile and a current database) to find the correct package name.
  • SSH push rejected "permission denied": Confirm your public key is saved in AUR account settings and that your SSH config uses the correct key. Test with ssh [email protected] help — a successful connection prints your AUR username.
  • Files installed to /usr/local inside pkgdir: The upstream build system defaults to /usr/local. Pass -DCMAKE_INSTALL_PREFIX=/usr, --prefix=/usr to configure, or set PREFIX=/usr for Makefile-based projects.
  • check() fails in a clean chroot but not locally: Use makepkg --check inside a clean chroot via extra-x86_64-build (from the devtools package) to catch missing test dependencies or environment assumptions.
tested on:Arch 2025-05

Frequently asked questions

Can I build AUR packages as root?
No. makepkg explicitly refuses to run as root for security reasons. Always build as a regular user; makepkg will call sudo or ask for a password only when installing dependencies or the finished package.
What is the difference between depends and makedepends?
depends lists packages required at runtime on the end-user's system. makedepends lists packages only needed during the build, such as cmake or meson; they can be absent once the package is installed.
How do I handle a VCS package like a -git package?
Append -git to pkgname, use a git+ source URL, and implement a pkgver() function that generates a version string from git rev-list and rev-parse. makepkg calls pkgver() automatically and updates the variable before packaging.
Do I need to use a clean chroot for AUR submissions?
It is strongly recommended. Build in a clean chroot using the devtools package (extra-x86_64-build) to confirm all dependencies are correctly declared and the build does not rely on packages installed only on your own machine.
How do I transfer maintainership or orphan a package?
Log in to aur.archlinux.org, navigate to your package page, and use the Manage Co-Maintainers or Disown Package options in the package actions sidebar. Orphaned packages are available for adoption by other AUR users.

Related guides