# Writing an abuild recipe An `abuild` file is a POSIX shell snippet that tells apkg how to build a package. The directory containing it must have the same name as the package. See `man apkg` for full details on all options and environment variables, and `man apkg-genabuild` for the recipe scaffolding tool. To quickly scaffold a new recipe from a source URL, use `apkg-genabuild`: ```sh apkg-genabuild https://example.com/mypkg-1.2.3.tar.gz ``` This creates the directory and a skeleton `abuild` with `name`, `version`, `release`, and `source` already populated. ## Directory structure ``` mypkg/ abuild - package recipe (required) info - package metadata template (description, homepage, license, maintainer) depends - dependency list, one per line (optional) preinstall - script run before the package is built (optional) postinstall - script run after the package is installed (optional) .shasum - source checksums, auto-generated (regenerate with `apkg -g`) .files - package file list, auto-generated (regenerate with `apkg -k`) ``` ## Minimal recipe ```sh name=mypkg version=1.2.3 release=1 source="https://example.com/$name-$version.tar.gz" ``` ### Required variables - **`name`**: package name. Must match the directory name exactly. - **`version`**: upstream version string. Use the `$name` and `$version` variables in the source URL so updates are easier. - **`release`**: an incrementing integer starting at 1. Reset to 1 when `version` changes. Bump when the package needs a rebuild without a source change. ## Source formats The `source` variable accepts a whitespace-separated list. Five formats are supported: - **`https://example.com/pkg-1.0.tar.gz`**: A remote URL, downloaded with curl - **`mypkg-1.0.tar.gz::https://example.com/v1.0.tar.gz`**: Custom local filename for a remote URL - **`https://example.com/pkg.tar.gz::noextract`**: Download but do not unpack - **`my-file`**: A local file in the recipe directory (not downloaded) - (empty): Create a meta/dummy package with only `/usr` Multiple sources can be specified: ```sh source="https://example.com/$name-$version.tar.gz fix-build.patch default-config::noextract" ``` If `source` is empty, apkg creates a dummy package: useful for meta packages that exist only to pull in dependencies. ## Optional variables ### Build control - **`build_type`**: force a specific build system instead of auto-detection. One of: `meson_build`, `configure_build`, `cmake_build`, `python_build`, `perlmodule_build`, `makefile_build`. - **`build_dir`**: subdirectory within the extracted source tree to enter before building. Useful when a tarball extracts into a differently-named directory. - **`build_opt`**: extra flags appended to the build system command. The defaults (`--prefix=/usr`, `--sysconfdir=/etc`, etc.) are always included; this adds on top. - **`skip_patch`**: set to `1` to skip automatic patch application. Use this if you need to call `apply_patch` manually from `build()`. - **`patch_opt`**: options for `patch(1)`. Default: `-p1`. ### Package content control - **`keep_static`**: set to keep `*.a` static libraries (removed by default). - **`keep_libtool`**: set to keep `*.la` libtool archives (removed by default). - **`keep_locale`**: set to keep locale files in `/usr/share/locale` and `/usr/lib/locale`. - **`keep_doc`**: set to keep documentation in `/usr/share/doc` and `/usr/doc`. - **`no_strip`**: set to skip ELF binary and library stripping. ### Runit services - **`sv`**: service files to install into `/etc/sv`. Accepts: - `run` → `/etc/sv/$name/run` - `finish` → `/etc/sv/$name/finish` - `.run` → `/etc/sv//run` - `.finish` → `/etc/sv//finish` - `.` → `/etc/sv//` ```sh sv="run finish mydaemon.run mydaemon.finish" ``` ## Build hooks ### Custom build function If a `build()` function is defined, it completely replaces the auto-detected build system. Two variables are available: - **`$SRC`**: where sources were extracted - **`$PKG`**: the fakeroot directory where files must be installed Several `DESTDIR`-style variables are pre-exported: `DESTDIR`, `DEST_DIR`, `INSTALLROOT`, `install_root`, `INSTALL_ROOT`. ```sh build() { cd "$SRC/$name-$version" ./configure --prefix=/usr --sysconfdir=/etc make make DESTDIR="$PKG" install } ``` `build()` runs with `set -ex`, so the script exits on any error and prints each command. ### Pre/post build hooks Without a `build()` function, you can use `prebuild()` and `postbuild()`: ```sh prebuild() { sed -i 's/broken/fixed/g' src/whatever.c } postbuild() { mv "$PKG/usr/bin/wrongname" "$PKG/usr/bin/rightname" } ``` The execution order is: `prebuild()` → auto-detected build system → `postbuild()`. ## Build system auto-detection When no `build()` is defined and no `build_type` is set, apkg checks for these files in order: 1. `meson.build`: meson with LTO, PIE, `wrap_mode=nodownload`, `buildtype=plain` 2. `configure`: autotools `./configure --prefix=/usr --sysconfdir=/etc ...` 3. `CMakeLists.txt`: cmake with `Release` build type, prefers ninja 4. `setup.py`: `python3 setup.py build && install --root=$PKG` 5. `Makefile.PL`: `perl Makefile.PL && make && make install` 6. `Makefile` / `makefile` / `GNUmakefile`: raw make with standard variables The exact flags for each build system are documented in `doc/defaultbuildopts`. ## Post-build processing After compilation, apkg automatically: - Compresses man pages (man1–man8 only, gzip) and info pages - Removes common conflict files: `fonts.dir`, `fonts.scale`, `perllocal.pod`, `charset.alias` - Removes static libraries (`*.a`), libtool archives (`*.la`), locales, and docs unless the corresponding `keep_*` variable is set - Strips ELF binaries (`--strip-all`), shared objects (`--strip-unneeded`), and static archives (`--strip-debug`) unless `no_strip` is set - Installs runit service files from the `sv` variable ## The info file `apkg-genabuild` creates an `info` file alongside the `abuild` with package metadata: ``` description: homepage: license: maintainer: name ``` Fill in each field as appropriate. The `maintainer` line uses the format `name `. ## The depends file One dependency per line. Lines starting with `#` are comments. Dependencies are just package names: no version constraints. ``` # Direct dependencies of mypkg zlib libpng freetype ``` Dependencies are recursive: when installing with `-I`, apkg will resolve the full tree. Only list direct dependencies; transitive ones are handled automatically. Use `apkg-redundantdeps` to find and clean up transitive entries. ## preinstall / postinstall scripts These are optional executable scripts in the recipe directory: - **`preinstall`**: runs before the package is built (only during `apkg -i` or `apkg -u`). Good for pre-flight checks or preparing the system. - **`postinstall`**: runs after the package is installed or upgraded. Good for one-time setup that can't be done at build time. If `APKG_ROOT` is set (alternative install root), these scripts run inside a chroot. ## Checksums and file lists - **`.shasum`**: sha3sum of each source file, auto-generated on first build. Regenerate with `apkg -g `. - **`.files`**: sorted list of every file in the built `.spm`, auto-generated after packaging. Regenerate with `apkg -k `. Used by `apkg -S` for file search. ## Complete example ```sh name=hello version=2.12.1 release=1 source="https://ftp.gnu.org/gnu/hello/$name-$version.tar.gz" build() { cd "$SRC/$name-$version" ./configure --prefix=/usr make make DESTDIR="$PKG" install } ``` With a `depends` file: ``` zlib ``` With a `postinstall` script: ```sh #!/bin/sh echo "hello was installed!" ``` ## Tips - Use `apkg-genabuild ` to scaffold a recipe from a source URL quickly. - Use `$name` and `$version` in source URLs so bumping the version only requires changing two variables. - Patches (`.patch` / `.diff` files) listed in `source` are applied automatically with `patch -p1` before the build. Use `patch_opt` to change the strip level. - Set `APKG_KEEP_WORKDIR=1` in your environment to inspect the build tree when debugging a failed build.