Building Freebsd Ports
Post covering how to build FreeBSD ports using poudriere and portshaker.
Back to an old platonic love
Lately, I had to came back to FreeBSD, and take over maintenance of some services deployed in FreeBSD.
I’ve been an happy FreeBSD years ago, I enjoyed this a lot, the handbook and other documentation are marvelous, many things “just works”, and I have a beard.
Long time ago I was also enjoying a very cool FreeBSD setup guide, from iMil. And together with GCU Squad they were spreading fun and love around the (BSD) world…
In fact I moved a bit away mainly due to lack of available time. You know, $WORK, $kids, $LIFE, … ^^
So thanks to $WORK, I know have the opportunity to dive again in the FreeBSD world.
I’ve got a few ports to maintain (including an old port of pydf I became the maintainer of, and that I was a bit ashamed to let rot due to lack of time…), and I’ve been recently looking at options for building the ports.
This page documents the steps I followed to set my building environment up.
My requirements - wishes
- I need a setup allowing to build ports that are managed in an overlay/separate port tree, typically managed in a Git repository.
- I want to build ports using FreeBSD Jails isolationg from the host OS and keeping it clear as much as possible.
- I want to reuse existing packages as much as possible, and especially avoid building big resouces hungry software like the compilers and buildrs like gcc, rust, and cmake. Especially as I currently don’t need any customisation there.
- Leveraging ZFS, especially as I need to become more acustonished to it.
Tooling
I ended up using a few tools:
- poudriere: to build ports in FreeBSD Jails
- portshaker: to keep ports tree udpated and merged. And also because it’s a
tool that I just discovered and that was in fact created by an old colleague, another memory from the past :)
Setting the tools up
I will make use of doas to run the commands as root.
Preparing for building in Jails with Poudriere
Installing poudriere, portshaker and friends
doas pkg update
doas pkg install poudriere git portshaker
Setting up poudriere
The first step is to create the ZFS dataset that will be used by poudriere.
# Find a suitable ZFS pool, for me it will be zroot
zpool list
# Create a ZFS dataset for poudriere
doas zfs create -o mountpoint=/poudriere zroot/poudriere
Now we have a nice ZFS dataset zroot/poudriere
mounted on /poudriere
and ready
to be used to host all poudriere-related things.
Configuring poudriere
The poudriere configuration is quite straigthforward, and I mainly add an issue with a single point:
- From the official doc and other posts I saw, it wasn’t clear to me how to
setup BASEFS properly, sawing many examples specifying a
ZROOTFS
, but keepingBASEFS
at another path.
Configuring /usr/local/etc/poudriere.conf
:
ZPOOL=zroot
ZROOTFS=/poudriere
FREEBSD_HOST=https://download.FreeBSD.org
RESOLV_CONF=/etc/resolv.conf
BASEFS=/poudriere
DISTFILES_CACHE=/usr/ports/distfiles
USE_PORTLINT=yes
USE_TMPFS=yes
NOLINUX=yes
ALLOW_MAKE_JOBS=yes
# Retrieve latest existing packages for all components
PACKAGE_FETCH_BRANCH=latest
# Except for the ones I manage
PACKAGE_FETCH_BLACKLIST="lua-resty-openidc lua-resty-session3 rbw"
Creating the build jail
I’m currently only interested in using the latest stable release, thus
currently 14.1-RELEASE
.
See poudriere-jail (8).;
# Create the build jail
doas poudriere jail -c -j 14-1-amd64 -v 14.1-RELEASE
Creating the ports tree
Poudriere will use a ports tree made of two souces:
- the upstream port tree, using it’s latest version
- a repository of custom ports
In order to do this, I will make use of portshaker
, and will just create an
empty poudriere ports tree that will later be filled using portshaker
.
See poudiere-ports (8)
for help on how to use poudriere ports
.
# Create an empty ports tree, named main
doas poudriere ports -cF -p main
# Create folder for distfiles
doas mkdir /poudriere/distfiles
# Check the ports tree that got created
poudriere ports -l
Setting up portshaker
So now we have a ports tree ready to be consumed by poudriere, but we need to populate it. I’m using portshaker for this.
Thanks Romain for porthshaker!
Creating a ZFS dataset for the portshaker cache
Optionally, it’s possible to create a dedicated volume for portshaker cache. It can be useful if the root ZFS volume is limited in space
doas zfs create -o mountpoint=/var/cache/portshaker zroot/portshaker
Configuring the ports trees portshaker will maintain and merge
Shells scripts are used to populate the source ports tree. For more details see potshaker.d (5)](https://man.freebsd.org/cgi/man.cgi?query=portshaker.d).
As already mentioned, I will need two ports tree sources:
- freebsd: the upstream FreeBSD ports tree
- custom: a git repository where I host the few ports I maintain
For the FreeBSD source, I use the official FreeBSD ports GitHub mirror.
Create /usr/local/etc/portshaker.d/freebsd
:
#!/bin/sh
. /usr/local/share/portshaker/portshaker.subr
if [ "$1" != '--' ]; then
err 1 "Extra arguments"
fi
shift
method="git"
git_clone_uri="https://git.freebsd.org/ports.git"
git_branch="main"
run_portshaker_command "$@"
Make the script executable:
$ chmod +x /usr/local/etc/portshaker.d/freebsd
For the custom source, I will use a public GitHub repositories that I manage: gwarf/freebsd-ports-custom.
I’m cloning using https
and not using ssh+git
as it’s a public repository
and as it is simpler, avoiding the need to care about authentication and
authorization.
In case authentication is required, you will have to ensure the root
user
can properly authenticate, using a personal authentication token, an SSH key
or else, as supported by the git client.
Create /usr/local/etc/portshaker.d/custom
:
#!/bin/sh
. /usr/local/share/portshaker/portshaker.subr
if [ "$1" != '--' ]; then
err 1 "Extra arguments"
fi
shift
method="git"
git_clone_uri="https://github.com/gwarf/freebsd-ports-custom.git"
git_branch="main"
run_portshaker_command "$@"
Make the script executable:
chmod +x /usr/local/etc/portshaker.d/custom
Configuring portshaker
The main configuration of potshaker
is in /usr/local/etc/portshaker.conf
, and an sample file is provided as
/usr/local/etc/portshaker.conf.sample
. The man page is helpful
portshaker.conf (5).
The goal of this configuration is to populate the /poudriere/ports
ports
tree that will be used by poudriere.
The custom
ports tree will be used as an overlay on the offical FreeBSD
ports tree, overwriting existing files, to update existing ports, and adding
new files and directories for adding new ports.
Create /usr/local/etc/portshaker.conf
:
# Directory to cache port trees
mirror_base_dir="/var/cache/portshaker"
use_zfs="yes"
ports_trees="main"
# Poudriere-related configuration
poudriere_dataset="zroot/poudriere"
poudriere_ports_mountpoint="/poudriere/ports"
# Merge trees in the empty `main` pourdriere ports tree prepared previously
main_poudriere_tree="main"
# Force overwritting files freebsd ports with custom overlay
# This doesn't remove non matching files
main_merge_from="freebsd custom+"
Using portshaker
The porthskare UX is quite simple, you will want to often use it without any parameter, meaning that it will update and merge all trees.
# Update a single port tree
doas portshaker -u freebsd
# Update all ports trees
doas portshaker -U
# Merge prot trees
doas porthakser -M
# Update and merge port trees
doas portshaker
Building the ports
I use /usr/local/etc/poudriere.d/pkglist
to document the list of ports to be
built, let’s first populate it:
# Populating the list of packages to be built
doas echo 'security/rbw' > /usr/local/etc/poudriere.d/pkglist
doas echo 'www/lua-resty-session' >> /usr/local/etc/poudriere.d/pkglist
Then it’s possible to build the ports with the jail template that was previously created.
# Updating and merging the trees
doas portshaker
# Building packages verbosely using the merged ports trees
doas poudriere bulk -f /usr/local/etc/poudriere.d/pkglist -j 14-1-amd64 -p main -v -v
The resulting ports will be in /poudriere/data/packages/14-1-amd64-main/
,
14-1-amd64
being the name of the jail used to build, and main
being the
name of the poudriere ports tree.
Using the ports
It is possible to access the repository locally.
Create repository definition in /usr/local/etc/pkg/repos/custom.conf
:
Custom: {
url: "file:///poudriere/data/packages/14-1-amd64-main"
}
Use the repository:
# Check repositories configuration
pkg -vv
# Update packages list
doas pkg update
# Search for a package, showing its origin
doas search -Q repository rbw
rbw-1.11.1
Repository : Custom [file:////poudriere/data/packages/14-1-amd64-main]
Comment : Unofficial Bitwarden cli
It is possible to serve directly or
rsync
this directory to a web server so that FreeBSD servers and jails can use it.
Testing a port in a jail
When working on ports, it’s also very convenient to use poudiere-testport (8) to test an individual port, before using it, and/or submitting it.
Adding the -i
parameter spawns an interactive shell at the end of the run,
allowing to do changes and tests. As the ports as built as the nobody
user,
it may be required to excalate to root via su -
.
doas poudriere testport -j 14-1-amd64 -p main -o security/rbw
To be followed
While I’m currently very happy with this setup, and all the tools I used, there are things to improve, like making use of ccache, or customising ports options.
I also need to find and document a simple/easy way to use poudriere to work on ports, like when bumping their versions or creating new ones. I’ve some notes on waht I currently do, but it’s not yet something I’m happy with.
References
Here is some documentation I followed to set this up, thanks to all the authors.
- FreeBSD Handbook: building packages with poudriere
- FreeBSD Porter’s Handbook: Testing with poudriere
- GitHub Poudriere wiki: portshaker
- Erwan Martin: Build your own FreeBSD ports and make packages out of them using jails, poudriere and portshaker
- Bert JW Regeer: Building Custom Ports With Poudriere And Portshaker
- FreeBSD forum: apply own patches with poudriere"
- Boris Tassou: FreeBSD: poudriere ou comment gérer ses paquets
- Poudriere: Getting Started - Tutorial