summaryrefslogtreecommitdiffstats
path: root/content/en/slackware/buildsystem/index.md
blob: 9db3f140175ed5e944c65bc0fd2f0f050fca0a68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
+++
title    = "Package buildsystem"
tagline  = "How I build and publish my personal slackware64-current package repository."
status   = "active"
tags     = ["slackware", "slackrepo", "packaging", "buildsystem"]

[menus.main]
  name   = "buildsystem"
  parent = "slackware"
  weight = 20
+++

My personal Slackware packages for **slackware64-current** are built by a small
pipeline of tools running inside one dedicated QEMU virtual machine. Nothing here
is a single program: it is a repository that gets reassembled, a dependency layer
that gets patched, a builder that turns SlackBuilds into packages, and a
publishing step that puts them online at
[packages.danix.xyz](https://packages.danix.xyz). This page walks the whole flow
in the order a build actually happens.

{{< image src="buildsystem-flow.svg" alt="Flowchart of the package buildsystem: assemble the repo with slackrepo_setup, fix -current dependencies with mkhint, build with slackrepo, and publish through the finish hooks, with a separate green side path for testing on Slackware 15.0 stable before submitting to SBo." caption="The pipeline end to end. The green side path is the 15.0 stable test, run only for packages headed to SlackBuilds.org." />}}

## The VM

The buildsystem lives in a QEMU virtual machine running **slackware64-current**,
kept up to date with `slackpkg` against a local mirror of Slackware's own system
packages. It has 8 CPU cores and around 8 GB of RAM, enough to build all but the
heaviest packages comfortably, and I reach it over SSH. Keeping it in its own VM
means a build, a broken dependency, or a full repository regeneration never
touches my daily driver: the box exists to be hammered and, if needed, thrown
away and rebuilt.

## Assembling the repository

Once a week the SlackBuilds tree is regenerated from scratch. It starts as a
clone of [Ponce's slackbuilds](https://github.com/Ponce/slackbuilds) checked out
on the `current` branch, the community tree that tracks SlackBuilds.org against
slackware-current. On top of that I overlay my own two collections as squashed
git subtrees: [my-slackbuilds](https://github.com/danixland/my-slackbuilds) for
general personal packages and
[Slackware-Pentesting-Suite](https://github.com/danixland/Slackware-Pentesting-Suite)
for security tooling.

Where a personal package shares a name with an upstream one, the upstream copy is
*shadowed*: its directory is removed so my version wins. The result is a single
local tree that is standard SBo plus my additions, ready to build. That whole
assembly is one script, which will get its own page here later.

## The -current dependency problem

SBo SlackBuilds target Slackware **stable**, so some of their build-time
dependencies are unnecessary on -current, which already ships them as system
packages or newer versions. `rust-opt` and `google-go-lang` are typical: needed
on stable, pointless on -current. These "phantom" dependencies would otherwise
force needless rebuilds.

slackrepo strips a dependency from a package with a per-package hint file carrying
`DELREQUIRES`, but writing one by hand for every affected package after each
weekly regeneration is exactly the tedium a script should own. That job belongs to
[mkhint](/slackware/mkhint/): its `-F` sweep reads a list of phantom deps and, for
every package whose requirements hit one, writes or merges the right
`DELREQUIRES` across the freshly rebuilt tree in a single pass.

{{< actions use="repo" url="https://git.danix.xyz/mkhintfile/" desc="Read the mkhint source" caption="Curious how the phantom-dep sweep actually works? The whole thing is one Bash script." >}}

## Building

The actual building is done by
[slackrepo](https://github.com/aclemons/slackrepo), an automated SlackBuild
builder for Slackware, now maintained by Andrew Clemons. It compiles each package and its dependencies in a clean
chroot, tracks upstream git revisions to work out what has changed and needs
rebuilding, and produces a repository that plugs straight into `slackpkg+`. I run
it with a start hook that first rebases my SlackBuilds tree onto upstream, so
every build starts from a current tree, and it handles the dependency ordering so
a single command rebuilds everything that moved.

## Publishing

When a build finishes, a chain of slackrepo finish hooks takes over. They
regenerate the `slackpkg+` repository metadata, build the styled HTML frontend for
the package site, sync the result out to the live server, and send a notification
that the run is done. The frontend wraps Apache's plain directory autoindex in a
themed header and footer so [packages.danix.xyz](https://packages.danix.xyz) reads
as a proper repository rather than a bare file listing. That frontend is its own
small project and will get a page here later too.

{{< actions use="repo" url="https://git.danix.xyz/pkgs-html-structure/" desc="See the frontend generator" caption="It is mostly a shell hook that walks the package tree and writes the header and footer HTML. Have a look under the hood." >}}

## Testing against 15.0 stable

Some of the packages I write are meant to be submitted upstream to
SlackBuilds.org, which targets Slackware **stable**, not -current. Since my whole
buildsystem is -current, a package building fine here proves nothing about 15.0.
Before I submit one, I test it with a separate, independent tool built for exactly
that: it resolves the SlackBuild's dependency tree locally, then builds and
installs every package in a fresh disposable overlay chroot layered over a clean,
read-only Slackware 15.0 base. That catches the current-versus-15.0 drift a
-current build hides.

It does not touch or drive slackrepo, and its built packages are throwaway: the
only question it answers is "does this still build clean on 15.0". One limit worth
naming: it shares the host kernel, so packages that build kernel modules still
want a real 15.0 VM. This tool will also get its own page here in time.

{{< actions use="repo" url="https://git.danix.xyz/sbo-batch-tester/" desc="Browse sbo-batch-tester" caption="The overlay-chroot and dependency-resolution logic live here if you want to read how the 15.0 test is built." >}}

## The weekly rhythm

Put together, the week is one repeatable cycle: regenerate the SlackBuilds tree,
sweep the phantom-dependency hints with `mkhint -F`, build and publish with
slackrepo and its hooks, and, for anything headed to SlackBuilds.org, spot-test it
against a clean 15.0 base first. Four small tools, each doing one job well, and a
disposable VM to run them in. Very Slackware.

I hope you found this walk through my buildsystem interesting. If you end up
running something similar, or you have questions, ideas, or suggestions about any
piece of it, drop me a line and I will gladly get in touch.

See you next time.

{{< actions use="repo" url="https://packages.danix.xyz" desc="Browse the package repository" caption="Everything the buildsystem produces lands here. If you run slackware64-current, you can point slackpkg+ at it and pull my packages straight in." >}}