Brain dump: OPTIONS, FLAVORS and SUBPACKAGES in FreeBSD Ports Framework |
Posted on February 7, 2024
This post is an attempt of mine to build a clear mental image of how OPTIONS, FLAVORS and SUBPACKAGES are related. I was told several times that this writeup is quite useful, I decided to put it there.
So, what are
- options? A way to change how the build is carried out. They can be seen as inputs to the build directory that affect the build directory and the resulting package. For instance, options allow turning software features on and off, thus increasing or reducing the amount of dependencies.
- subpackages? A feature of Ports that allows producing multiple packages from a single build directory (or in other words, pkg-plist)
- flavors? Another feature of Ports that allows, on one hand, altering the way software is build (like OPTIONS), but on another hand producing a separate package for each flavor. This also means that flavorized ports have multiple build directories. This, in turn, allows for different port inputs to end up in the same repository as different packages.
Before we proceed let’s underline the following idea. A single Makefile may produce several build directories via flavors and each build may produce several packages via subpackages:
/+++++++++++++++\
| |
==> | foo-flav1.pkg |
/+++++++++++++++\ / | |
/++++++++++\ | | | \+++++++++++++++/
| | ======> | work-flavor1/ | ======*
| Makefile | | | |
| | ====\ \+++++++++++++++/ | /+++++++++++++++\
\++++++++++/ | \ | |
| /+++++++++++++++\ ===> | foo-flav2.pkg |
| | | | |
\======> | work-flavor2/ | \+++++++++++++++/
| |
\+++++++++++++++/
Now, what are
- master/slave ports? An idiom when master port’s Makefile acts as a template and slave Makefile includes it to override some variables or targets. It allows you have multiple Makefiles that shares code that would otherwise be duplicated.
When do I use options?
- A project’s build system provides a way to turn some features on and off. There are recommended defaults, but you want to provide more flexibility for Ports consumers.
- You don’t expect other ports to depend on the specific option value. Options can’t be depended on, however it is possible to abuse flavors for that.
When do I use subpackages?
- A project consists of a library, a CLI frontend program and a GUI frontend program. It is a good candidate for subpackaging, especially if the project’s build system doesn’t allow building programs against installed library.
- A software library that has wrappers for popular frameworks in its tree. For example, libappstream base library has adaptor libraries for Qt and GLib.
- A software library that has bindings to other programming languages. Note that the common property of all these cases is that there is some “base” code that would otherwise be compiled multiple times.
- If you have master/slave ports which follow the same build procedure but then
remove some files from the
STAGEDIR
to make packages different - they are begging for being subpackaged.
When do I use flavors?
- When a project targets some framework and we have several versions of that framework in our Tree.
- For a Python application port we may want to have a package for each Python version we’re currently supporting.
- A C++ library that uses Qt may be compiled against Qt 5 and Qt 6. Note the important thing that for an application the choice between Qt 5 and Qt 6 should probably be at the options level! This is because in the library case we might want to depend on the specific Qt version and like we said before, flavors are dependable options. But applications are rarely depended on, so it is better to use options in this case.
- The
haskell-language-server
is a special sort of Haskell program that depends on the compiler being used. We have several Haskell compiler versions in the tree sohaskell-language-server
is flavorized based on this. - The common property here is that we produce a package for each flavor and resulting packages can coexist in the repository (and even possibly on the target system!)
- You can abuse flavors as a dependable options. Creating a flavor that has
the desired option always set to on would produce you a package that can be
used in
*_DEPENDS
line. Keep in mind that this isn’t what flavors were incepted for, so always look for ways to solve the problem differently.
When do I use master/slave ports?
- The ability for slave port to override any variable or target of the master port is very powerful. This approach can do everything that flavors do, but its generality makes it harder to grasp and maintain.
- Slave ports might come in handy when you want it to reside in a separate
category/port
directory. For example, a slave port might require a completely different set of patches infiles/
than master one. - With flavors and subpackages at our disposal, the master/slave ports should only be considered as a last resort.