title: Arch Linux Packaging Guide *Generated using [Claude.ai](https://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 1. [Overview](#1-overview) 2. [Prerequisites and Setup](#2-prerequisites-and-setup) 3. [Understanding the PKGBUILD File](#3-understanding-the-pkgbuild-file) 4. [PKGBUILD Variables Reference](#4-pkgbuild-variables-reference) 5. [PKGBUILD Functions](#5-pkgbuild-functions) 6. [Building Packages with makepkg](#6-building-packages-with-makepkg) 7. [VCS Package Guidelines](#7-vcs-package-guidelines) 8. [Testing and Quality Assurance](#8-testing-and-quality-assurance) 9. [Submitting to the AUR](#9-submitting-to-the-aur) 10. [Package Maintenance](#10-package-maintenance) 11. [Best Practices and Common Mistakes](#11-best-practices-and-common-mistakes) 12. [Quick Reference](#12-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 ```bash # 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`: ```bash # 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 ```bash 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: 1. **Metadata variables** - Package name, version, description, etc. 2. **Source information** - Where to download source files 3. **Functions** - How to build and package the software ### PKGBUILD Template Use the official prototype as a starting point: ```bash cp /usr/share/pacman/PKGBUILD.proto ~/packages/mypackage/PKGBUILD ``` ### Minimal PKGBUILD Example ```bash # Maintainer: Your Name 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:** ```bash # 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 `_` to create architecture-specific overrides: ```bash 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. ```bash 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](#7-vcs-package-guidelines). ### build() - Compilation Optional (but usually needed). Compiles the source code. ```bash 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. ```bash check() { cd "$srcdir/$pkgname-$pkgver" make check # or: make test # or: ctest --test-dir build } ``` ### package() - Installation **Required.** Installs files into `$pkgdir`. ```bash 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: ```bash 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 ```bash 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 ```bash # Generate and append to PKGBUILD makepkg -g >> PKGBUILD # Or use updpkgsums (from pacman-contrib) updpkgsums ``` ### Install the Built Package ```bash # 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: - `-git` for Git - `-svn` for Subversion - `-hg` for Mercurial - `-bzr` for Bazaar ### VCS Source Format ```bash # 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: ```bash 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):** ```bash 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:** ```bash 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:** ```bash pkgver() { cd "$srcdir/$pkgname" printf "r%s.%s" "$(hg identify -n)" "$(hg identify -i)" } ``` **Subversion:** ```bash pkgver() { cd "$srcdir/$pkgname" printf "r%s" "$(svnversion | tr -d 'A-z')" } ``` ### Complete VCS PKGBUILD Example ```bash # Maintainer: Your Name 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 1. **Don't commit pkgver bumps alone** - Only commit when PKGBUILD changes 2. **Use provides/conflicts** - Link to the stable package name 3. **Add VCS tool to makedepends** - `git`, `subversion`, `mercurial`, etc. 4. **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: ```bash # 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):** ```bash # 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):** ```bash # Install from AUR yay -S clean-chroot-manager # Create chroot sudo ccm c # Build package sudo ccm s ``` ### Testing the Package ```bash # 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 ```bash # 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 1. **Read the guidelines** - Familiarize yourself with [Arch package guidelines](https://wiki.archlinux.org/title/Arch_package_guidelines) 2. **Create an AUR account** - Register at https://aur.archlinux.org 3. **Set up SSH keys** - Required for pushing packages ### Setting Up SSH Authentication ```bash # 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 ```bash # 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.** ```bash # 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 1. **No duplicates** - Don't submit packages already in official repos 2. **Must be useful** - Packages should benefit the community 3. **Must be legal** - Comply with licensing terms 4. **x86_64 only** - Packages must support x86_64 5. **No replaces for AUR** - Don't use `replaces` unless renaming a package 6. **Maintain your packages** - Respond to comments and keep packages updated ### Updating an AUR Package ```bash 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: 1. Flag it as out-of-date with details 2. Email the maintainer if possible 3. After 2 weeks with no response, file an orphan request ### Adopting Orphaned Packages Orphaned packages can be adopted by any registered AUR user: ```bash # 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 ```bash package() { make install # Files go to real system! } ``` **Right:** ```bash package() { make DESTDIR="$pkgdir" install } ``` --- **Wrong:** Hardcoded paths ```bash source=("https://example.com/myapp-1.0.0.tar.gz") ``` **Right:** ```bash source=("https://example.com/${pkgname}-${pkgver}.tar.gz") ``` --- **Wrong:** Missing direct dependency ```bash depends=('qt5-base') # Missing qt5-svg even though app uses it ``` **Right:** ```bash depends=('qt5-base' 'qt5-svg') # Both are direct dependencies ``` --- **Wrong:** Version with hyphen ```bash pkgver=1.0.0-beta1 ``` **Right:** ```bash 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 ```bash # 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](https://wiki.archlinux.org/title/Creating_packages) - [PKGBUILD - ArchWiki](https://wiki.archlinux.org/title/PKGBUILD) - [Arch package guidelines](https://wiki.archlinux.org/title/Arch_package_guidelines) - [AUR submission guidelines](https://wiki.archlinux.org/title/AUR_submission_guidelines) - [VCS package guidelines](https://wiki.archlinux.org/title/VCS_package_guidelines) - [makepkg man page](https://man.archlinux.org/man/makepkg.8) - [PKGBUILD man page](https://man.archlinux.org/man/PKGBUILD.5) --- *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.*