Generated using Claude.ai (Opus 4.5 model)
Complete Guide to Creating Arch Linux Packages
A comprehensive guide consolidating official Arch Linux documentation on creating, building, and submitting packages to the Arch User Repository (AUR).
Table of Contents
- Overview
- Prerequisites and Setup
- Understanding the PKGBUILD File
- PKGBUILD Variables Reference
- PKGBUILD Functions
- Building Packages with makepkg
- VCS Package Guidelines
- Testing and Quality Assurance
- Submitting to the AUR
- Package Maintenance
- Best Practices and Common Mistakes
- Quick Reference
1. Overview
What is an Arch Linux Package?
An Arch package is a tar archive compressed with zstd (.pkg.tar.zst) containing:
- Binary files to install
.PKGINFO- Package metadata (name, version, dependencies, etc.).MTREE- Hashed list of files with permissions for integrity verification.BUILDINFO- Information for reproducible builds.INSTALL- Optional post-install/upgrade/remove script.Changelog- Optional changelog maintained by the packager
The Arch Build System
The Arch Build System (ABS) is a ports-like system for building packages from source:
| Component | Description |
|---|---|
| PKGBUILD | Bash script containing build instructions and metadata |
| makepkg | Tool that reads PKGBUILDs and creates packages |
| pacman | Package manager for installing/removing packages |
| devtools | Tools for building in clean chroots (official packages) |
Package Repositories
- Official Repositories (core, extra, multilib): Pre-built binary packages maintained by Arch developers
- Arch User Repository (AUR): Community-maintained PKGBUILDs (not pre-built)
2. Prerequisites and Setup
Install Required Tools
# Install base development tools (required)
sudo pacman -S base-devel
# Install additional useful tools
sudo pacman -S namcap devtools git
The base-devel group includes: autoconf, automake, binutils, bison, fakeroot, file, findutils, flex, gawk, gcc, gettext, grep, groff, gzip, libtool, m4, make, pacman, patch, pkgconf, sed, sudo, texinfo, which.
Configure makepkg (Optional)
Edit /etc/makepkg.conf or ~/.makepkg.conf:
# Use multiple cores for compilation
MAKEFLAGS="-j$(nproc)"
# Use multiple cores for compression
COMPRESSZST=(zstd -c -z -q -T0 -)
# Enable ccache for faster rebuilds (optional)
# BUILDENV=(... ccache ...)
Set Up a Working Directory
mkdir -p ~/packages
cd ~/packages
3. Understanding the PKGBUILD File
What is a PKGBUILD?
A PKGBUILD is a Bash script that defines how to build a package. It contains:
- Metadata variables - Package name, version, description, etc.
- Source information - Where to download source files
- Functions - How to build and package the software
PKGBUILD Template
Use the official prototype as a starting point:
cp /usr/share/pacman/PKGBUILD.proto ~/packages/mypackage/PKGBUILD
Minimal PKGBUILD Example
# Maintainer: Your Name <your.email@example.com>
pkgname=hello-world
pkgver=1.0.0
pkgrel=1
pkgdesc="A simple hello world program"
arch=('x86_64')
url="https://example.com/hello-world"
license=('MIT')
depends=('glibc')
source=("https://example.com/${pkgname}-${pkgver}.tar.gz")
sha256sums=('abc123...')
build() {
cd "$srcdir/$pkgname-$pkgver"
./configure --prefix=/usr
make
}
package() {
cd "$srcdir/$pkgname-$pkgver"
make DESTDIR="$pkgdir" install
}
4. PKGBUILD Variables Reference
Mandatory Variables
| Variable | Description |
|---|---|
pkgname |
Package name (lowercase alphanumerics, @._+-). Cannot start with - or . |
pkgver |
Upstream version. No hyphens allowed (replace with _) |
pkgrel |
Arch-specific release number. Starts at 1, increment for PKGBUILD fixes |
arch |
Supported architectures: ('x86_64') or ('any') for arch-independent |
Recommended Variables
| Variable | Description |
|---|---|
pkgdesc |
Brief description (≤80 chars). Don’t include package name |
url |
Upstream project URL |
license |
SPDX license identifier(s): ('GPL-3.0-or-later'), ('MIT'), etc. |
Dependency Arrays
| Variable | Description |
|---|---|
depends |
Runtime dependencies (required to run the software) |
makedepends |
Build-time only dependencies (not needed at runtime) |
checkdepends |
Dependencies for running tests (only needed for check()) |
optdepends |
Optional dependencies with descriptions: ('python: for scripting support') |
Important: Always list all direct dependencies, even if they’re pulled in transitively. Transitive dependencies can change.
Source Arrays
| Variable | Description |
|---|---|
source |
Array of source files (URLs or local filenames) |
sha256sums |
SHA-256 checksums for each source (or 'SKIP' to skip verification) |
validpgpkeys |
GPG key fingerprints for signature verification |
noextract |
Files to not auto-extract |
Source URL best practices:
# Use variables for maintainability
source=("https://github.com/user/repo/archive/v${pkgver}.tar.gz")
# Rename downloaded files
source=("${pkgname}-${pkgver}.tar.gz::https://example.com/download/${pkgver}.tar.gz")
# Local files (must be in same directory as PKGBUILD)
source=("fix-build.patch"
"myconfig.conf")
Other Useful Variables
| Variable | Description |
|---|---|
provides |
Virtual packages this provides: ('libfoo.so=1-64') |
conflicts |
Packages that conflict with this one |
replaces |
Packages this replaces (use sparingly, mostly for renames) |
backup |
Config files to backup on upgrade: ('etc/myapp.conf') |
options |
Build options: ('!strip' '!buildflags' 'staticlibs') |
install |
Post-install script filename: install=${pkgname}.install |
changelog |
Changelog filename |
epoch |
Force package to be seen as newer (use sparingly) |
groups |
Package groups this belongs to |
Architecture-Specific Variables
Append _<arch> to create architecture-specific overrides:
source_x86_64=("https://example.com/binary-x86_64.tar.gz")
sha256sums_x86_64=('...')
depends_x86_64=('lib32-glibc')
5. PKGBUILD Functions
Available Variables in Functions
| Variable | Description |
|---|---|
$srcdir |
Directory where sources are extracted |
$pkgdir |
Fake root directory for installation (becomes package contents) |
$startdir |
Directory containing the PKGBUILD (deprecated, avoid using) |
prepare() - Source Preparation
Optional. Runs after source extraction. Used for patching and source modifications.
prepare() {
cd "$srcdir/$pkgname-$pkgver"
# Apply patches
patch -Np1 -i "$srcdir/fix-build.patch"
# Generate build files
autoreconf -fiv
}
pkgver() - Dynamic Version (VCS Packages)
Optional. Used to update pkgver from VCS sources. See VCS Package Guidelines.
build() - Compilation
Optional (but usually needed). Compiles the source code.
build() {
cd "$srcdir/$pkgname-$pkgver"
# Standard autotools
./configure --prefix=/usr
make
# Or CMake
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr
cmake --build build
# Or Meson
arch-meson build
meson compile -C build
}
Important: Always use --prefix=/usr. Arch packages should never install to /usr/local.
check() - Testing
Optional but recommended. Runs the test suite.
check() {
cd "$srcdir/$pkgname-$pkgver"
make check
# or: make test
# or: ctest --test-dir build
}
package() - Installation
Required. Installs files into $pkgdir.
package() {
cd "$srcdir/$pkgname-$pkgver"
# Standard make install
make DESTDIR="$pkgdir" install
# Install license
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
# Install documentation
install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md"
# Install config file (add to backup array)
install -Dm644 myapp.conf "$pkgdir/etc/myapp.conf"
}
Note: Everything in $pkgdir will be packaged. The directory structure under $pkgdir becomes the root filesystem structure.
Split Packages
Build multiple packages from one PKGBUILD:
pkgbase=myproject
pkgname=('myproject' 'myproject-docs')
# ... other variables ...
package_myproject() {
pkgdesc="The main application"
depends=('glibc')
cd "$srcdir/$pkgbase-$pkgver"
make DESTDIR="$pkgdir" install
}
package_myproject-docs() {
pkgdesc="Documentation for myproject"
arch=('any')
cd "$srcdir/$pkgbase-$pkgver"
install -Dm644 docs/* -t "$pkgdir/usr/share/doc/$pkgbase/"
}
6. Building Packages with makepkg
Basic Usage
cd ~/packages/mypackage
# Build the package
makepkg
# Build and install dependencies automatically
makepkg -s
# Build, install deps, and install the package
makepkg -si
# Build and remove makedepends afterward
makepkg -sr
# Clean build directory after successful build
makepkg -c
Useful makepkg Options
| Option | Description |
|---|---|
-s, --syncdeps |
Install missing dependencies with pacman |
-r, --rmdeps |
Remove makedepends after build |
-i, --install |
Install package after building |
-c, --clean |
Clean up work files after build |
-f, --force |
Overwrite existing package |
-C, --cleanbuild |
Remove $srcdir before building |
-o, --nobuild |
Download and extract only (no build) |
-e, --noextract |
Don’t extract sources (use existing $srcdir) |
-R, --repackage |
Repackage without rebuilding |
-g, --geninteg |
Generate integrity checksums |
--nocheck |
Skip the check() function |
--skippgpcheck |
Skip PGP signature verification |
--skipchecksums |
Skip checksum verification |
-L, --log |
Log build output to file |
Generate Checksums
# Generate and append to PKGBUILD
makepkg -g >> PKGBUILD
# Or use updpkgsums (from pacman-contrib)
updpkgsums
Install the Built Package
# Using pacman
sudo pacman -U mypackage-1.0.0-1-x86_64.pkg.tar.zst
# Or using makepkg -i
makepkg -si
7. VCS Package Guidelines
Naming Convention
VCS packages must be suffixed with the VCS type:
-gitfor Git-svnfor Subversion-hgfor Mercurial-bzrfor Bazaar
VCS Source Format
# Git (most common)
source=("git+https://github.com/user/repo.git")
# Git with specific branch
source=("git+https://github.com/user/repo.git#branch=develop")
# Git with specific tag
source=("git+https://github.com/user/repo.git#tag=v1.0.0")
# Git with specific commit
source=("git+https://github.com/user/repo.git#commit=abc123")
# SSH URL
source=("git+ssh://git@github.com/user/repo.git")
For VCS sources, use SKIP for checksums:
sha256sums=('SKIP')
The pkgver() Function
The pkgver() function dynamically generates version numbers from VCS sources.
Recommended format: RELEASE.rREVISION or RELEASE.rREVISION.gHASH
Git with tags (preferred):
pkgver() {
cd "$srcdir/$pkgname"
git describe --long --tags --abbrev=7 | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
# Output: 1.2.3.r5.gabc1234 (5 commits after tag v1.2.3)
Git without tags:
pkgver() {
cd "$srcdir/$pkgname"
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short=7 HEAD)"
}
# Output: r150.abc1234 (150 commits, hash abc1234)
Mercurial:
pkgver() {
cd "$srcdir/$pkgname"
printf "r%s.%s" "$(hg identify -n)" "$(hg identify -i)"
}
Subversion:
pkgver() {
cd "$srcdir/$pkgname"
printf "r%s" "$(svnversion | tr -d 'A-z')"
}
Complete VCS PKGBUILD Example
# Maintainer: Your Name <email@example.com>
pkgname=myapp-git
_pkgname=myapp
pkgver=1.2.3.r5.gabc1234
pkgrel=1
pkgdesc="My application (development version)"
arch=('x86_64')
url="https://github.com/user/myapp"
license=('MIT')
depends=('glibc')
makedepends=('git' 'cmake')
provides=("${_pkgname}")
conflicts=("${_pkgname}")
source=("git+${url}.git")
sha256sums=('SKIP')
pkgver() {
cd "$srcdir/$_pkgname"
git describe --long --tags --abbrev=7 | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
build() {
cmake -B build -S "$_pkgname" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr
cmake --build build
}
package() {
DESTDIR="$pkgdir" cmake --install build
install -Dm644 "$srcdir/$_pkgname/LICENSE" \
"$pkgdir/usr/share/licenses/$pkgname/LICENSE"
}
VCS Package Rules
- Don’t commit pkgver bumps alone - Only commit when PKGBUILD changes
- Use provides/conflicts - Link to the stable package name
- Add VCS tool to makedepends -
git,subversion,mercurial, etc. - pkgrel stays at 1 - Reset when pkgver changes, increment only for PKGBUILD fixes
8. Testing and Quality Assurance
Using namcap
namcap analyzes PKGBUILDs and packages for common errors:
# Check PKGBUILD
namcap PKGBUILD
# Check built package
namcap mypackage-1.0.0-1-x86_64.pkg.tar.zst
# Check installed package
namcap -i mypackage
Common namcap warnings:
| Warning | Meaning |
|---|---|
dependency X detected and target Y depends on it |
Missing dependency |
dependency X included but already satisfied |
Redundant dependency |
ELF file has no RELRO |
Security issue (missing hardening) |
Dependency included, but may not be needed |
Possible unnecessary dependency |
Note: namcap can produce false positives. Investigate warnings but don’t blindly follow all suggestions.
Building in a Clean Chroot
Building in a clean chroot ensures: - All dependencies are correctly declared - No accidental linking against packages on your system - Reproducible builds
Using devtools (recommended for AUR maintainers):
# Install devtools
sudo pacman -S devtools
# Build in clean chroot
pkgctl build
# Or use the repository-specific script
extra-x86_64-build
Using clean-chroot-manager (alternative):
# Install from AUR
yay -S clean-chroot-manager
# Create chroot
sudo ccm c
# Build package
sudo ccm s
Testing the Package
# List package contents
pacman -Qlp mypackage-1.0.0-1-x86_64.pkg.tar.zst
# View package info
pacman -Qip mypackage-1.0.0-1-x86_64.pkg.tar.zst
# Install and test
sudo pacman -U mypackage-1.0.0-1-x86_64.pkg.tar.zst
# Verify installation
pacman -Ql mypackage
pacman -Qi mypackage
# Test the software actually works
mypackage --version
Checking Dependencies
# Find libraries linked by an executable
ldd /usr/bin/myapp
# Better alternative
lddtree /usr/bin/myapp
# Find which package provides a library
pacman -Qo /usr/lib/libfoo.so
9. Submitting to the AUR
Prerequisites
- Read the guidelines - Familiarize yourself with Arch package guidelines
- Create an AUR account - Register at https://aur.archlinux.org
- Set up SSH keys - Required for pushing packages
Setting Up SSH Authentication
# Generate a dedicated SSH key for AUR
ssh-keygen -t ed25519 -f ~/.ssh/aur
# Configure SSH
cat >> ~/.ssh/config << EOF
Host aur.archlinux.org
IdentityFile ~/.ssh/aur
User aur
EOF
# Copy public key to AUR profile
cat ~/.ssh/aur.pub
# Paste this into "My Account" > "SSH Public Key" on AUR website
Creating a New AUR Package
# Clone the (empty) AUR repository
git -c init.defaultBranch=master clone ssh://aur@aur.archlinux.org/pkgname.git
cd pkgname
# You'll see: "warning: You appear to have cloned an empty repository."
# This is expected for new packages
# Add your PKGBUILD
cp ~/packages/mypackage/PKGBUILD .
# Generate .SRCINFO (REQUIRED)
makepkg --printsrcinfo > .SRCINFO
# Add files
git add PKGBUILD .SRCINFO
# Commit
git commit -m "Initial upload"
# Push
git push
The .SRCINFO File
The .SRCINFO file is a machine-readable representation of PKGBUILD metadata. It must be regenerated and committed whenever PKGBUILD changes.
# Generate .SRCINFO
makepkg --printsrcinfo > .SRCINFO
# Always commit both files together
git add PKGBUILD .SRCINFO
git commit -m "Update to version X.Y.Z"
git push
AUR Submission Rules
- No duplicates - Don’t submit packages already in official repos
- Must be useful - Packages should benefit the community
- Must be legal - Comply with licensing terms
- x86_64 only - Packages must support x86_64
- No replaces for AUR - Don’t use
replacesunless renaming a package - Maintain your packages - Respond to comments and keep packages updated
Updating an AUR Package
cd ~/aur/mypackage
# Update PKGBUILD
# ... edit PKGBUILD ...
# Regenerate .SRCINFO
makepkg --printsrcinfo > .SRCINFO
# Commit and push
git add PKGBUILD .SRCINFO
git commit -m "Update to version X.Y.Z"
git push
10. Package Maintenance
Responding to Feedback
- Monitor comments on your AUR package page
- Address bug reports and feature requests
- Thank users for helpful feedback
- Don’t leave comments for every version update
Flagging Out-of-Date Packages
If you find an unmaintained package:
- Flag it as out-of-date with details
- Email the maintainer if possible
- After 2 weeks with no response, file an orphan request
Adopting Orphaned Packages
Orphaned packages can be adopted by any registered AUR user:
# Clone the existing repository
git clone ssh://aur@aur.archlinux.org/pkgname.git
# Make your changes and push
Deletion Requests
Submit deletion requests for: - Duplicate packages - Packages moved to official repos - Abandoned/broken packages with no maintainer
11. Best Practices and Common Mistakes
Do’s
✅ Use HTTPS sources when available
✅ Verify sources with checksums and PGP signatures
✅ Use $pkgname and $pkgver variables in source URLs
✅ List all direct dependencies even if transitively satisfied
✅ Test in a clean chroot before submitting
✅ Use --prefix=/usr for configure scripts
✅ Include licenses in /usr/share/licenses/$pkgname/
✅ Use install command instead of cp for proper permissions
✅ Add backup array for config files in /etc
Don’ts
❌ Never install to /usr/local - Arch packages use /usr
❌ Never modify $srcdir outside of prepare()
❌ Don’t use sudo in functions - makepkg handles privileges
❌ Avoid custom variables without _ prefix - May conflict with makepkg
❌ Don’t skip checksums without good reason
❌ Don’t use replaces in AUR packages - Use conflicts instead
❌ Don’t leave empty directories in packages
❌ Don’t include .git directories in packages
Common Mistakes
Wrong: Installing with DESTDIR missing
package() {
make install # Files go to real system!
}
Right:
package() {
make DESTDIR="$pkgdir" install
}
Wrong: Hardcoded paths
source=("https://example.com/myapp-1.0.0.tar.gz")
Right:
source=("https://example.com/${pkgname}-${pkgver}.tar.gz")
Wrong: Missing direct dependency
depends=('qt5-base') # Missing qt5-svg even though app uses it
Right:
depends=('qt5-base' 'qt5-svg') # Both are direct dependencies
Wrong: Version with hyphen
pkgver=1.0.0-beta1
Right:
pkgver=1.0.0_beta1
12. Quick Reference
Minimal PKGBUILD Checklist
☐ pkgname (lowercase, valid characters)
☐ pkgver (no hyphens)
☐ pkgrel=1
☐ pkgdesc (≤80 chars)
☐ arch=('x86_64') or arch=('any')
☐ url
☐ license (SPDX identifier)
☐ depends (all direct runtime deps)
☐ makedepends (build-only deps)
☐ source (with variables)
☐ sha256sums (or valid checksums)
☐ build() or package() function
☐ package() function (required)
Common Commands
# Build package
makepkg -s
# Build and install
makepkg -si
# Generate checksums
makepkg -g >> PKGBUILD
# or: updpkgsums
# Generate .SRCINFO
makepkg --printsrcinfo > .SRCINFO
# Check PKGBUILD with namcap
namcap PKGBUILD
# Check built package
namcap *.pkg.tar.zst
# Build in clean chroot
pkgctl build
# List package contents
pacman -Qlp *.pkg.tar.zst
# Install local package
sudo pacman -U *.pkg.tar.zst
File Locations
| Location | Purpose |
|---|---|
/usr/bin/ |
Executables |
/usr/lib/ |
Libraries |
/usr/share/ |
Architecture-independent data |
/usr/share/doc/$pkgname/ |
Documentation |
/usr/share/licenses/$pkgname/ |
License files |
/usr/share/man/ |
Man pages |
/etc/ |
System configuration (add to backup array) |
Useful Links
- Creating packages - ArchWiki
- PKGBUILD - ArchWiki
- Arch package guidelines
- AUR submission guidelines
- VCS package guidelines
- makepkg man page
- PKGBUILD man page
This guide consolidates information from the official Arch Linux Wiki and man pages. For the most up-to-date information, always refer to the official documentation.