Improve the way you make use of FreeBSD in your company.
Find out more about what makes us the most reliable FreeBSD development organization, and take the next step in engaging with us for your next FreeBSD project.
FreeBSD Support FreeBSD DevelopmentAdditional Articles
Here are more interesting articles on FreeBSD that you may find useful:
- Debunking Common Myths About FreeBSD
- GPL 3: The Controversial Licensing Model and Potential Solutions
- Our 2023 Recommended Summer Reads 2023 FreeBSD and Linux
- FreeBSD – Linux and FreeBSD Firewalls – Part 2
- FreeBSD – 3 Advantages to Running FreeBSD as Your Server Operating System
Without a doubt, modern package management is one of the most convenient tools of open-source operating systems. 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, to optimize them for a certain device, or maybe you are managing a specific cluster or fleet of FreeBSD devices.
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 port documentation won’t be required.
This can be set or unset globally by adding OPTIONS_SET+=DOCS or OPTIONS_UNSET+=DOCS to your make.conf(5).
Both OPTIONS 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:
- A jail
- A checkout of the FreeBSD ports tree
- 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 for which the resulting packages will be built—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 to 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
This article provides 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.
officeklara
Learn About KlaraWhat makes us different, is our dedication to the FreeBSD project.
Through our commitment to the project, we ensure that you, our customers, are always on the receiving end of the best development for FreeBSD. With our values deeply tied into the community, and our developers a major part of it, we exist on the border between your infrastructure and the open source world.