AUR Packages

In this article i will review how AUR packages are defined. I used to create rpm and debian packages, but switched recently to use Arch Linux. As such makes sense to review how to create a aur package and how does it works the ecosystem.

Arch Packages

The Arch User Repository (AUR) is a community-driven repository for Arch users. It contains package descriptions (PKGBUILDs) that allow you to compile a package from source with makepkg and then install it via pacman. The AUR was created to organize and share new packages from the community and to help expedite popular packages’ inclusion into the extra repository.

Getting Started

  1. Ensure base-devel is installed.
  2. Adjust /etc/makepkg.conf

/etc/makepkg.conf

You may wish to adjust /etc/makepkg.conf to optimize the build process to your system prior to building packages from the AUR. A significant improvement in package build times can be realized on systems with multi-core processors by adjusting the MAKEFLAGS variable, by using multiple cores for compression, or by using different compression algorithm. Users can also enable hardware-specific compiler optimizations via the CFLAGS variable.

I will just adjust the parallelism for compilation to use the 8-cores I have

MAKEFLAGS="-j8"

The overall flags seem to be very optimized already, checkout the article if you want to go into that rabbit hole

Installing and upgrading packages

Installing packages from the AUR is a relatively simple process. Essentially:

  1. Acquire the build files, including the PKGBUILD and possibly other required files, like systemd units and patches (often not the actual code).
  2. Verify that the PKGBUILD and accompanying files are not malicious or untrustworthy.
  3. Run makepkg in the directory where the files are saved. This will download the code, compile it, and package it.
  4. Run pacman -U package_file to install the package onto your system.

Acquire build files

Locate the package in the AUR. This is done using the search field at the top of the AUR home page. Clicking the application’s name in the search list brings up an information page on the package. Read through the description to confirm that this is the desired package, note when the package was last updated, and read any comments.

Clone git the repository for the package

git clone https://aur.archlinux.org/package_name.git

Acquire a PGP public key if needed

Check if a signature file in the form of .sig or .asc is part of the PKGBUILD source array. If that is the case, then acquire one of the public keys listed in the PKGBUILD validpgpkeys array

Build the package

Change directories to the directory containing the package’s PKGBUILD.

$ cd package_name
$ makepkg -si

Install the package

The package can now be installed with pacman:

pacman -U package_name-version-architecture.pkg.tar.zst

Lets test …

Using one example package paru. one can use the following commands

Let’s check available updates with paru

paru -Qua

PKGBUILD

The following manpage PKGBUILD(5) provides more in-depth information regarding the PKBUILD package description file.

Creating Packages

Overview

Packages in Arch Linux are built using the makepkg utility and the information stored in a PKGBUILD file. When makepkg runs, it searches for a PKGBUILD in the current directory and follows the instructions in it to acquire the required files and/or compile them to be packed within a package file (pkgname.pkg.tar.zst). The resulting package contains binary files and installation instructions ready to be installed by pacman.

An Arch package is no more than a tar archive, or ‘tarball’, compressed using zstd(1), which contains the following files generated by makepkg:

  • The binary files to install.
  • .PKGINFO: contains all the metadata needed by pacman to deal with packages, dependencies, etc.
  • .BUILDINFO: contains information needed for reproducible builds. This file is present only if a package is built with pacman 5.1 or newer. See BUILDINFO(5).
  • .MTREE: contains hashes and timestamps of the files, which are included in the local database so that pacman can verify the integrity of the package.
  • .INSTALL: an optional file used to execute commands after the install/upgrade/remove stage. (This file is present only if specified in the PKGBUILD.)
  • .Changelog: an optional file kept by the package maintainer documenting the changes of the package. (It is not present in all packages.)

Preparation

First, ensure that the necessary tools are installed: the meta package base-devel should be sufficient; it pulls in make and additional tools needed for compiling from source.

The key tool for building packages is makepkg (provided by pacman), which does the following:

  1. Checks if package dependencies are installed.
  2. Downloads the source file(s) from the specified server(s).
  3. Unpacks the source file(s).
  4. Compiles the software and installs it under a fakeroot environment.
  5. Strips symbols from binaries and libraries.
  6. Generates the package meta file which is included with each package.
  7. Compresses the fakeroot environment into a package file.
  8. Stores the package file in the configured destination directory, which is the current working directory by default.

Download the source tarball of the software you want to package, extract it, and follow the author’s steps to install the program. Make a note of all commands and/or steps needed to compile and install it. You will be repeating those same commands in the PKGBUILD file.

Most software authors stick to the 3-step build cycle:

./configure
make
make install

Creating a PKGBUILD

To start building a new package, first create a new directory for the package and change current directory into this one. Then, a PKGBUILD file needs to be created: a prototype PKGBUILD found in /usr/share/pacman/ can be used or you can start from a PKGBUILD from another package. The latter may be a good choice if a similar package already exists.

makepkg defines two variables that you should use as part of the build and install process:

  • srcdir: This points to the directory where makepkg extracts or symlinks all files in the source array.
  • pkgdir: This points to the directory where makepkg bundles the installed package, which becomes the root directory of your built package.

PKGBUILD functions

When building a package, makepkg will invoke the following five functions if they have been defined in the PKGBUILD. Function package() is required in every PKGBUILD and will always be invoked. If any of the other functions is not defined, makepkg will simply skip the invocation of that function.

  • prepare(): With this function, commands that are used to prepare sources for building are run, such as patching. This function runs right after package extraction, before pkgver() and the build function. If extraction is skipped (makepkg --noextract), then prepare() is not run

  • pkgver(): pkgver() runs after the sources are fetched, extracted and prepare() executed. So you can update the pkgver variable during a makepkg stage. This is particularly useful if you are making git/svn/hg/etc. packages, where the build process may remain the same, but the source could be updated every day, even every hour.

  • build(): Now, you need to implement the build() function in the PKGBUILD file. This function uses common shell commands in Bash syntax to automatically compile software and create a directory called pkg to install the software to. This allows makepkg to package files without having to sift through your file system.

  • check(): Place for calls to make check and similar testing routines. It is highly recommended to have check() as it helps to make sure software has been built correctly and works fine with its dependencies.

  • package(): The final step is to put the compiled files in a directory where makepkg can retrieve them to create a package. This by default is the pkg directory—a simple fakeroot environment. The pkg directory replicates the hierarchy of the root file system of the software’s installation paths. If you have to manually place files under the root of your filesystem, you should install them in the pkg directory under the same directory structure. For example, if you want to install a file to /usr/bin, it should instead be placed under $pkgdir/usr/bin. Very few install procedures require the user to copy dozens of files manually. Instead, for most software, calling make install will do so.

Lets create our package

For testing purposes lets create a hello world application in rust and package it as a new AUR

Create a new directory for this app (make sure you have rust installed)

cargo new myhello
cd myhello
cargo run

Great we have a Hello World App

Let’s clean up

cargo clean

You should have this structure

.
├── Cargo.lock
├── Cargo.toml
└── src
└── main.rs

Lets add a cargo module to generate our PKGBUILD file

cargo install cargo-aur

Let’s add some Metadata required for generating the AUR on Cargo.toml file

[package]
name = "myhello"
version = "0.1.0"
edition = "2021"

authors = ["Rui Ramos", "Rui Ramos <no-reply@rust-lang.org>"]
description = "A HelloWorld Application for AUR testing purposes"
homepage="https://rramos.github.io"
repository = "https://github.com/rramos/rust-helloworld.git"
license = "MIT"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

For a complete list please check the Cargo Manifest page.

Now run the following command

cargo aur

We now have a PKGBUILD package generated for this application with something similar

# Maintainer: Rui Ramos
# Maintainer: Rui Ramos <no-reply@rust-lang.org>
#
# This PKGBUILD was generated by `cargo aur`: https://crates.io/crates/cargo-aur

pkgname=myhello-bin
pkgver=0.1.0
pkgrel=1
pkgdesc="A HelloWorld Application for AUR testing purposes"
url="https://rramos.github.io"
license=("MIT")
arch=("x86_64")
provides=("myhello")
conflicts=("myhello")
source=("https://github.com/rramos/rust-helloworld.git/releases/download/v$pkgver/myhello-$pkgver-x86_64.tar.gz")
sha256sums=("ef8ce03c73185ef872116c17971c21f6f8f2c8f67d42a5c0b4ca876d164191b2")

package() {
install -Dm755 myhello -t "$pkgdir/usr/bin"
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
}

It also generated a tarball for the application myhello-0.1.0-x86_64.tar.gz .

Now lets use pacman to build and install the package

makepkg -si

You should now have a executable myhello application congrats.

Clean Up

Let’s remove our application using the command

sudo pacman -R myhello-bin

Checking package sanity

After testing package functionality, check it for errors using namcap

$ namcap PKGBUILD
$ namcap <package file name>.pkg.tar.zst

Submitting packages to the AUR

In order to contribute to the community one can submit the AUR package. For that read AUR submission guidelines for a detailed description of the submission process.

You would need one ssh account and key.

If you are developing in Rust I would advise following the guide from Manoj Karthick

Conclusion

AUR packages seem quite similar to debian or rpm packages in a sense that you need to specify a set of instructions for compiling and installing, and those functions would be called by the packaging system. I liked the simplified structure of it and cargo-aur package is amazing for rust developers who want to quickly prepare and package their applications.

On the article I didn’t deep dive on more complex preparation/compilation options that some applications have or dependencies. Also is important to check the Arch guidelines if you intend to release your application for the community and also follow good practices not only for the package build but also files organization.

In general as a past RedHat, Debian and Gentoo Linux user, I’m really becoming a fan of this packaging system.

Hope this helps, the following References section contains the source of information used to consolidate this article.

References