freebsd ports and packages

Customizing FreeBSD Ports and Packages

Customizing FreeBSD Ports and Packages

An easy introduction into the package manager that FreeBSD has to offer. Learn how to get access to binaries and how to compile them.

Without a doubt, one of the most convenient tools of modern open-source operating systems is the package manager. The ability to search, download, and install a wide range of pre-compiled software with only a single command is unparalleled. FreeBSD is no exception here, providing access to binary packages via the pkg(8) utility. However, these packages must all be compiled somewhere, and package consumers are at the mercy of the package producer when it comes to the contents and compile-time options used.

This article is for anyone who is looking to step into the world of building their own FreeBSD package sets. There are many reasons to do so; perhaps you want finer grained control over the contents or your packages, or optimize them for a certain device, or maybe you are managing a specific cluster or fleet of FreeBSD devices.

Existing experience with using FreeBSD’s ports framework would be beneficial to the reader, although it is not strictly required.

Port Options

The simplest customization that can be made to individual ports is through each port’s options menu. These options are defined to include/exclude certain functionality from the program(s), or otherwise influence the final package contents. Simple ports may have no options, while larger or more heavily used software may have a dozen or more. All of this is at the discretion of the port maintainer.

Executing make config in a port’s directory will bring up an options menu similar to the following:

$ cd sysutils/tmux
$ make config

┌──────────────────────────────── tmux-3.1c ───────────────────────────────────┐
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │+[ ] BACKSPACE        Build with tty/keys patch                           │ │
│ │+[x] DOCS             Build and/or install documentation                  │ │
│ │+[x] EXAMPLES         Build and/or install examples                       │ │
│ │+[ ] LIBEVENT_STATIC  Build with static libevent                          │ │
│ │+[ ] UTF8PROC         Build with utf8proc support                         │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────────────────────────────┤
│                       <  OK  >            <Cancel>                           │
└──────────────────────────────────────────────────────────────────────────────┘

Although the exact set of options provided is unique to the port in question, there are several options that are common to many ports. The DOCS option shown above is one such example. As you might imagine, unsetting this globally could be useful for saving disk and/or network space on installations where it is known that the port documentation won’t be required.

This can be unset globally by adding OPTIONS_UNSET+=DOCS to your make.conf(5). Conversely, OPTIONS_SET can be used to globally enable certain options. Both variables accept a space-separated list of options, and can be overwritten by an individual port’s configuration. For more information on using these variables, see ports(7).

A few other common options that may be useful are EXAMPLES, NLS, X11, CUPS. Readers are encouraged to explore these options and their effects, and to search out others.

Did you know?

65% of businesses running on FreeBSD have less incidents and faster to go-to-market of their products with professional support!

Building Custom Package Sets with Poudriere

The FreeBSD ports tree is designed so that it can be driven by a single make invocation at any level. There is power in such simplicity, particularly in its ability to be wrapped or automated by other tools. The most popular of any such tools is poudriere(8), a tool for building FreeBSD packages in bulk.

Anyone who expects to build packages from source regularly should learn to use poudriere. There are many guides out there for how to set up and configure the tool, so we will not focus on that here. Instead, we will focus on the basic usage required for building and configuring packages.

Binding in Bulk

Building packages with poudriere(8) is done with the bulk command. This process requires three things:

  1. A jail
  2. A checkout of the FreeBSD ports tree
  3. A list of ports to be built

Jails provide a clean environment in which packages can be built, free of any existing programs or libraries on the host. They also define the version of FreeBSD which the resulting packages will be built for; packages built in a 12.2-RELEASE jail will be built to run on a 12.2-RELEASE system, even if the host machine is running 13-STABLE.

Jails can be constructed by poudriere itself with the jail subcommand. The name must be specified with -j and the FreeBSD version with -v.

$ poudriere jail -c -j 13_0_release -m ftp -v 13.0-RELEASE
$ poudriere jail -c -j 14_current -m git -v main

The above example creates two new and distinct jails. 13_0_release will be fetched from the official release distribution sets, and runs a 13.0-RELEASE userland. 14_current will be built from source, using a checkout of the latest git revision.

Next, a ports tree checkout is required. poudriere allows you to fetch a new one, or provide the path to an existing checkout. The following example creates two such ports trees:

$ poudriere ports -c -p 2021q1 -m git -B 2020q1
$ poudriere ports -c -p dev -m null -M $HOME/freebsd-ports

2020q1 consists of a freshly checked-out tree from version control, based on the 2021q1 branch in git. dev was created as a special unmanaged ports tree using an existing checkout at $HOME/freebsd-ports – useful for testing customizations.

Finally, a list of ports is required. This list can be provided on the commandline, or as the contents of a text file. The following command will generate a properly formatted list of port origins for the packages installed on the host:

$ pkg info -ao | awk '{ print $2 }' | sort > portlist.txt

With this set up, we can start building.

$ poudriere bulk -j 13_0_release -p dev -f portlist.txt

This command is enough to build all of the ports listed in portlist.txt in the 13_0_release jail, based on the ports tree dev. Hopefully, it is clear that swapping out the jail or ports tree in this command would result in a unique set of packages. This ability to build distinct packages sets from differing versions of FreeBSD or port sources is one of the key features that makes poudriere such a powerful tool.

Configuration Options

We’ve seen how to set port options in the previous section. Now we will look at how this is managed when using poudriere(8).

Setting options for an individual port is done with the options command. Like the bulk command, options accepts the -j jail and -p ports-tree arguments, optionally. This offers a lot of flexibility because it enables you to configure an individual port’s options on a per-tree or per-tree-and-jail tuple basis.

To make this clearer, consider the following invocations:

$ poudriere options -p dev sysutils/tmux
$ poudriere options -j 13_0_release -p dev sysutils/tmux

The first line sets the selected options for sysutils/tmux on all builds using dev, while the second line only takes effect when building with the 13_0_release jail as well. To configure options globally across all ports, poudriere allows for make.conf(5) files to be specified with similar granularity as above. These files are stored in the /usr/local/etc/poudriere.d/ directory. From the poudriere(8) man page, any of the following are possible:

Any of the following are allowed and will all be used in the order shown:

    /usr/local/etc/poudriere.d/make.conf
    /usr/local/etc/poudriere.d/<setname>-make.conf
    /usr/local/etc/poudriere.d/<tree>-make.conf
    /usr/local/etc/poudriere.d/<jailname>-make.conf
    /usr/local/etc/poudriere.d/<tree>-<setname>-make.conf
    /usr/local/etc/poudriere.d/<jailname>-<tree>-make.conf
    /usr/local/etc/poudriere.d/<jailname>-<setname>-make.conf
    /usr/local/etc/poudriere.d/<jailname>-<tree>-<setname>-make.conf

Note that <setname> is not considered here.

So, to apply custom options only ports built in the 14_current jail on the 2021q1 branch, you would do the following:

echo 'OPTIONS_UNSET=DOCS EXAMPLES X11' > /usr/local/etc/poudriere.d/14_current-2021q1-make.conf

Further Reading

The purpose of this article was to provide a brief introduction to the tools and options required for producing a customized set of FreeBSD packages. However, we have only scratched the surface of what is possible with poudriere(8) and the FreeBSD ports infrastructure.

The FreeBSD Handbook and Porter’s Handbook both provide chapters on poudriere, discussing other details of its setup and usage.

The previously mentioned ports(7) man page describes some of the make(1) variables that influence the ports tree, along with other details of its usage.

Finally, there are many other blog posts and tutorials related to poudriere, in which users describe their particular setup. When planning how to build and distribute packages, you could search and see if someone has already documented a similar use-case.

Like this article? Share it!

You might also be interested in

Get more out of your FreeBSD development

Kernel development is crucial to many companies. If you have a FreeBSD implementation or you’re looking at scoping out work for the future, our team can help you further enable your efforts.

More on this topic

freebsd networking

FreeBSD Network Troubleshooting: Understanding Network Performance

Network performance is one of the most complex topics to analyse and understand. FreeBSD has a full set of debugging features, and the network stack reports a ton of information. So much that it can be hard to figure out what is relevant and what is not. In this article, we define performance, look at how to measure what is available and how to get the system to report what it is managing to do.

freebsd network virtualized

Routing and Firewalling VLANS with FreeBSD

VNET virtual network stacks are a powerful network stack isolation technology that gives FreeBSD jails super powers. Follow our guide to use VLANs on FreeBSD, combine VLANs and VNETs and use VLANs with VNET Jails. Learn useful tricks with many exemplifying instances.

freebsd network virtualized

Virtualize Your Network on FreeBSD with VNET

FreeBSD Jails – a well-known feature that has become core to many excellent tools on FreeBSD such as the Poudriere package builder. Jails offer process and file system isolation, but for a long time they did not offer very satisfying network isolation. Learn how to isolate networks, how to test potentially hazardous firewall changes and how to do proper jail networking.

2 Comments on “Customizing FreeBSD Ports and Packages

  1. Pingback: Valuable News – 2021/04/11 | 𝚟𝚎𝚛𝚖𝚊𝚍𝚎𝚗

  2. Pingback: Building Customized FreeBSD Images | Klara Inc.

Tell us what you think!