# port test /usr/ports/net/csup
Chapter 10. Testing the Port
Table of Contents
10.1. Running make describe
Several of the FreeBSD port maintenance tools, such as portupgrade(1), rely on a database called /usr/ports/INDEX which keeps track of such items as port dependencies.
INDEX is created by the top-level ports/Makefile via make index
, which descends into each port subdirectory and executes make describe
there.
Thus, if make describe
fails in any port, no one can generate INDEX, and many people will quickly become unhappy.
It is important to be able to generate this file no matter what options are present in make.conf, so please avoid doing things such as using |
If make describe
produces a string rather than an error message, everything is probably safe.
See bsd.port.mk for the meaning of the string produced.
Also note that running a recent version of portlint
(as specified in the next section) will cause make describe
to be run automatically.
10.2. Running make test
Even if the port builds fine, it is a good idea to ensure that the software correctly does what it is supposed to do. If the original upstream project provides tests along with the software, it is a good idea to run them and check everything works as expected.
A port can enable tests automatically by using the TEST_TARGET
variable.
When set, this variable contains the name of the testing target of the port.
This is usually just test
but other names include tests
, check
or for
specific cases things like run_tests.py
.
In addition to the TEST_TARGET
variable the framework provides the following
variables to control the tests execution:
TEST_WRKSRC
is the directory to do the tests in.TEST_ENV
contains additional variables to be passed to the test stage.TEST_ARGS
contains any extra arguments passed to the test stage.
Examples of use of these variables can be found in cad/xyce, www/libjwt and others.
Please make sure that tests do not break when updating a port. |
10.3. Portclippy / Portfmt
Those tools come from ports-mgmt/portfmt.
Portclippy is a linter that checks if variables in the Makefile are in the correct order according to Order of Variables in Port Makefiles.
Portfmt is a tool for automatically formatting Makefile.
10.4. Portlint
Do check the port with portlint
before submitting or committing it.
portlint
warns about many common errors, both functional and stylistic.
For a new port, portlint -A
is the most thorough; for an existing port, portlint -C
is sufficient.
Since portlint
uses heuristics to try to figure out errors, it can produce false positive warnings.
In addition, occasionally something that is flagged as a problem really cannot be done in any other way due to limitations in the ports framework.
When in doubt, the best thing to do is ask on FreeBSD ports mailing list.
10.5. Port Tools
The ports-mgmt/porttools program is part of the Ports Collection.
port
is the front-end script, which can help simplify the testing job.
Whenever a new port or an update to an existing one needs testing, use port
test
to test the port, including the portlint
checking.
This command also detects and lists any files that are not listed in pkg-plist.
For example:
10.6. PREFIX
and DESTDIR
PREFIX
determines where the port will be installed.
It defaults to /usr/local, but can be set by the user to a custom path like /opt.
The port must respect the value of this variable.
DESTDIR
, if set by the user, determines the complete alternative environment, usually a jail or an installed system mounted somewhere other than /.
A port will actually install into DESTDIR/PREFIX, and register with the package database in DESTDIR/var/db/pkg.
DESTDIR
is handled automatically by the ports infrastructure with chroot(8).
There is no need for modifications or any extra care to write DESTDIR
-compliant ports.
The value of PREFIX
will be set to LOCALBASE
(defaulting to /usr/local).
If USE_LINUX_PREFIX
is set, PREFIX
will be LINUXBASE
(defaulting to /compat/linux).
Avoiding hard-coded /usr/local paths in the source makes the port much more flexible and able to cater to the needs of other sites.
Often, this can be accomplished by replacing occurrences of /usr/local in the port’s various Makefiles with ${PREFIX}
.
This variable is automatically passed down to every stage of the build and install processes.
Make sure the application is not installing things in /usr/local instead of PREFIX
.
A quick test for such hard-coded paths is:
% make clean; make package PREFIX=/var/tmp/`make -V PORTNAME`
If anything is installed outside of PREFIX
, the package creation process will complain that it cannot find the files.
In addition, it is worth checking the same with the stage directory support (see Staging):
% make stage && make check-plist && make stage-qa && make package
check-plist
checks for files missing from the plist, and files in the plist that are not installed by the port.stage-qa
checks for common problems like bad shebang, symlinks pointing outside the stage directory, setuid files, and non-stripped libraries…
These tests will not find hard-coded paths inside the port’s files, nor will it verify that LOCALBASE
is being used to correctly refer to files from other ports.
The temporarily installed port in /var/tmp/make -V PORTNAME
must be tested for proper operation to make sure there are no problems with paths.
PREFIX
must not be set explicitly in a port’s Makefile.
Users installing the port may have set PREFIX
to a custom location, and the port must respect that setting.
Refer to programs and files from other ports with the variables mentioned above, not explicit pathnames.
For instance, if the port requires a macro PAGER
to have the full pathname of less
, do not use a literal path of /usr/local/bin/less.
Instead, use ${LOCALBASE}
:
-DPAGER=\"${LOCALBASE}/bin/less\"
The path with LOCALBASE
is more likely to still work if the system administrator has moved the whole /usr/local tree somewhere else.
All these tests are done automatically when running |
10.7. poudriere
For a ports contributor, poudriere is one of the most important and helpful testing and build tools. Its main features include:
Bulk building of the entire ports tree, specific subsets of the ports tree, or a single port including its dependencies
Automatic packaging of build results
Generation of build log files per port
Providing a signed pkg(8) repository
Testing of port builds before submitting a patch to the FreeBSD bug tracker or committing to the ports tree
Testing for successful ports builds using different options
Because poudriere performs its building in a clean jail(8) environment and uses zfs(8) features, it has several advantages over traditional testing on the host system:
No pollution of the host environment: No leftover files, no accidental removals, no changes of existing configuration files.
Verify pkg-plist for missing or superfluous entries
Ports committers sometimes ask for a poudriere log alongside a patch submission to assess whether the patch is ready for integration into the ports tree
It is also quite straightforward to set up and use, has no dependencies, and will run on any supported FreeBSD release. This section shows how to install, configure, and run poudriere as part of the normal workflow of a ports contributor.
The examples in this section show a default file layout, as standard in FreeBSD.
Substitute any local changes accordingly.
The ports tree, represented by ${PORTSDIR}
, is located in /usr/ports.
Both ${LOCALBASE}
and ${PREFIX}
are /usr/local by default.
10.7.1. Installing poudriere
poudriere is available in the ports tree in ports-mgmt/poudriere. It can be installed using pkg(8) or from ports:
# pkg install poudriere
or
# make -C /usr/ports/ports-mgmt/poudriere install clean
There is also a work-in-progress version of poudriere which will eventually become the next release. It is available in ports-mgmt/poudriere-devel. This development version is used for the official FreeBSD package builds, so it is well tested. It often has newer interesting features. A ports committer will want to use the development version because it is what is used in production, and has all the new features that will make sure everything is exactly right. A contributor will not necessarily need those as the most important fixes are backported to released version. The main reason for the use of the development version to build the official package is because it is faster, in a way that will shorten a full build from 18 hours to 17 hours when using a high end 32 CPU server with 128GB of RAM. Those optimizations will not matter a lot when building ports on a desktop machine.
10.7.2. Setting Up poudriere
The port installs a default configuration file, /usr/local/etc/poudriere.conf. Each parameter is documented in the configuration file.
Here is a minimal example config file:
ZPOOL=zroot BASEFS=/usr/local/poudriere DISTFILES_CACHE=/usr/ports/distfiles RESOLV_CONF=/etc/resolv.conf
ZPOOL
The name of the ZFS storage pool which poudriere shall use. Must be listed in the output of
zpool status
.BASEFS
The root mount point for poudriere file systems. This entry will cause poudriere to mount
tank/poudriere
to/poudriere
.DISTFILES_CACHE
Defines where distfiles are stored. In this example, poudriere and the host share the distfiles storage directory. This avoids downloading tarballs which are already present on the system. Please create this directory if it does not already exist so that poudriere can find it.
RESOLV_CONF
Use the host /etc/resolv.conf inside jails for DNS. This is needed so jails can resolve the URLs of distfiles when downloading. It is not needed when using a proxy. Refer to the default configuration file for proxy configuration.
10.7.3. Creating poudriere Jails
Create the base jails which poudriere will use for building:
# poudriere jail -c -j 131Ramd64 -v 13.1-RELEASE -a amd64
Fetch a 13.1-RELEASE
for amd64
from the FTP server given by FREEBSD_HOST
in poudriere.conf,
create the zfs file system tank/poudriere/jails/131Ramd64
,
mount it on /poudriere/jails/131Ramd64 and extract the 13.1-RELEASE
tarballs into this file system.
# poudriere jail -c -j 12i386 -v stable/12 -a i386 -m git+https
Create tank/poudriere/jails/12i386
, mount it on /poudriere/jails/12i386,
then check out the tip of the Git branch of FreeBSD-12-STABLE
from GIT_HOST
in poudriere.conf or the default git.freebsd.org
into /poudriere/jails/12i386/usr/src,
then complete a buildworld
and install it into /poudriere/jails/12i386.
While it is possible to build a newer version of FreeBSD on an older version, most of the time it will not run.
For example, if a |
To create a poudriere jail for
In order to run a |
A list of jails currently known to poudriere can be shown with poudriere jail -l
:
# poudriere jail -l
JAILNAME VERSION ARCH METHOD
131Ramd64 13.1-RELEASE amd64 ftp
12i386 12.4-STABLE i386 git+https
10.7.4. Keeping poudriere Jails Updated
Managing updates is very straightforward. The command:
# poudriere jail -u -j JAILNAME
updates the specified jail to the latest version available. For FreeBSD releases, update to the latest patchlevel with freebsd-update(8). For FreeBSD versions built from source, update to the latest git revision in the branch.
For jails employing a
|
10.7.5. Setting Up Ports Trees for Use with poudriere
There are multiple ways to use ports trees in poudriere. The most straightforward way is to have poudriere create a default ports tree for itself, using Git:
# poudriere ports -c -m git+https -B main
These commands create tank/poudriere/ports/default
, mount it on /poudriere/ports/default, and populate it using Git.
Afterward it is included in the list of known ports trees:
# poudriere ports -l
PORTSTREE METHOD TIMESTAMP PATH
default git+https 2020-07-20 04:23:56 /poudriere/ports/default
Note that the "default" ports tree is special.
Each of the build commands explained later will implicitly use this ports tree unless specifically specified otherwise.
To use another tree, add |
The best way to deal with local modifications for a ports contributor is to use Git. As with the creation of jails, it is possible to use a different method for creating the ports tree. To add an additional ports tree for testing local modifications and ports development, checking out the tree via git (as described above) is preferable.
10.7.6. Using Manually Managed Ports Trees with poudriere
Depending on the workflow, it can be extremely helpful to use ports trees which are maintained manually. For instance, if there is a local copy of the ports tree in /work/ports, point poudriere to the location:
# poudriere ports -c -m null -M /work/ports -p development
This will be listed in the table of known trees:
# poudriere ports -l
PORTSTREE METHOD TIMESTAMP PATH
development null 2020-07-20 05:06:33 /work/ports
The dash or |
10.7.7. Keeping poudriere Ports Trees Updated
As straightforward as with jails described earlier:
# poudriere ports -u -p PORTSTREE
Will update the given PORTSTREE, one tree given by the output of poudriere -l
, to the latest revision available on the official servers.
Ports trees without a method, see Using Manually Managed Ports Trees with poudriere, cannot be updated like this and must be updated manually by the porter. |
10.7.8. Testing Ports
After jails and ports trees have been set up, the result of a contributor’s modifications to the ports tree can be tested.
For example, local modifications to the www/firefox port located in /work/ports/www/firefox can be tested in the previously created 13.1-RELEASE jail:
# poudriere testport -j 131Ramd64 -p development -o www/firefox
This will build all dependencies of Firefox. If a dependency has been built previously and is still up-to-date, the pre-built package is installed. If a dependency has no up-to-date package, one will be built with default options in a jail. Then Firefox itself is built.
The complete build of every port is logged to /poudriere/data/logs/bulk/131Ri386-development/build-time/logs.
The directory name 131Ri386-development
is derived from the arguments to -j
and -p
, respectively.
For convenience, a symbolic link /poudriere/data/logs/bulk/131Ri386-development/latest is also maintained.
The link points to the latest build-time directory.
Also in this directory is an index.html for observing the build process with a web browser.
By default, poudriere cleans up the jails and leaves log files in the directories mentioned above.
To ease investigation, jails can be kept running after the build by adding -i
to testport
:
# poudriere testport -j 131Ramd64 -p development -i -o www/firefox
After the build completes, and regardless of whether it was successful, a shell is provided within the jail.
The shell is used to investigate further.
poudriere can be told to leave the jail running after the build finishes with -I
.
poudriere will show the command to run when the jail is no longer needed.
It is then possible to jexec(8) into it:
# poudriere testport -j 131Ramd64 -p development -I -o www/firefox
[...]
====>> Installing local Pkg repository to /usr/local/etc/pkg/repos
====>> Leaving jail 131Ramd64-development-n running, mounted at /poudriere/data/.m/131Ramd64-development/ref for interactive run testing
====>> To enter jail: jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root
====>> To stop jail: poudriere jail -k -j 131Ramd64 -p development
# jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root
# [do some stuff in the jail]
# exit
# poudriere jail -k -j 131Ramd64 -p development
====>> Umounting file systems
An integral part of the FreeBSD ports build infrastructure is the ability to tweak ports to personal preferences with options.
These can be tested with poudriere as well.
Adding the -c
:
# poudriere testport -c -o www/firefox
Presents the port configuration dialog before the port is built.
The ports given after -o
in the format category/portname
will use the specified options, all dependencies will use the default options.
Testing dependent ports with non-default options can be accomplished using sets,
see Using Sets.
When testing ports where pkg-plist is altered during build depending on the selected options, it is recommended to perform a test run with all options selected and one with all options deselected. |
10.7.9. Using Sets
For all actions involving builds, a so-called set can be specified using -z setname
.
A set refers to a fully independent build.
This allows, for instance, usage of testport
with non-standard options for the dependent ports.
To use sets, poudriere expects an existing directory structure similar to PORT_DBDIR
, defaults to /var/db/ports in its configuration directory.
This directory is then nullfs(5)-mounted into the jails where the ports and their dependencies are built.
Usually a suitable starting point can be obtained by recursively copying the existing PORT_DBDIR
to /usr/local/etc/poudriere.d/jailname-portname-setname-options.
This is described in detail in poudriere(8).
For instance, testing www/firefox in a specific set named devset
, add the -z devset
parameter to the testport
command:
# poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox
This will look for the existence of these directories in this order:
/usr/local/etc/poudriere.d/131Ramd64-development-devset-options
/usr/local/etc/poudriere.d/131Ramd64-devset-options
/usr/local/etc/poudriere.d/131Ramd64-development-options
/usr/local/etc/poudriere.d/devset-options
/usr/local/etc/poudriere.d/development-options
/usr/local/etc/poudriere.d/131Ramd64-options
/usr/local/etc/poudriere.d/options
From this list, poudriere nullfs(5)-mounts the first existing directory tree into the /var/db/ports directory of the build jails.
Hence, all custom options are used for all the ports during this run of testport
.
After the directory structure for a set is provided, the options for a particular port can be altered. For example:
# poudriere options -c www/firefox -z devset
The configuration dialog for www/firefox is shown, and options can be edited.
The selected options are saved to the devset
set.
poudriere is very flexible in the option configuration. poudriere can be set for particular jails, ports trees, and for multiple ports by one command. Refer to poudriere(8) for details. |
10.7.10. Providing a Custom make.conf File
Similar to using sets, poudriere will also use a custom make.conf if it is provided. No special command line argument is necessary. Instead, poudriere looks for existing files matching a name scheme derived from the command line. For instance:
# poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox
causes poudriere to check for the existence of these files in this order:
/usr/local/etc/poudriere.d/make.conf
/usr/local/etc/poudriere.d/devset-make.conf
/usr/local/etc/poudriere.d/development-make.conf
/usr/local/etc/poudriere.d/131Ramd64-make.conf
/usr/local/etc/poudriere.d/131Ramd64-development-make.conf
/usr/local/etc/poudriere.d/131Ramd64-devset-make.conf
/usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf
Unlike with sets, all of the found files will be appended, in that order, into one make.conf inside the build jails. It is hence possible to have general make variables, intended to affect all builds in /usr/local/etc/poudriere.d/make.conf. Special variables, intended to affect only certain jails or sets can be set in specialised make.conf files, such as /usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf.
To build a set with a non default Perl version, for example, 5.20
, using a set named perl5-20
, create a perl5-20-make.conf with this line:
DEFAULT_VERSIONS+= perl=5.20
10.7.11. Pruning no Longer Needed Distfiles
poudriere comes with a built-in mechanism to remove outdated distfiles that are no longer used by any port of a given tree. The command
# poudriere distclean -p portstree
will scan the distfiles folder, DISTFILES_CACHE
in poudriere.conf,
versus the ports tree given by the -p portstree
argument and prompt for removal of those distfiles.
To skip the prompt and remove all unused files unconditionally, the -y
argument can be added:
# poudriere distclean -p portstree -y
10.8. Debugging ports
Sometimes things go wrong and the port fails at run time. The framework provides some facilities to help in debugging ports. These helpers are limited since the way of debugging a port heavily depends on the technology used. The following variables help with debugging ports:
WITH_DEBUG
. If set, ports are built with debugging symbols.WITH_DEBUG_PORTS
. Specifies a list of ports to be built withWITH_DEBUG
set.DEBUG_FLAGS
. Used to specify additional flags toCFLAGS
. Defaults to-g
.
When WITH_DEBUG
is set, either globally or for a list of ports, the resulting
binaries are not stripped.
These variables can be specified in make.conf or in the command line:
# cd category/port && make -DWITH_DEBUG DEBUG_FLAGSS="-g -O0"
If the port is built using ports-mgmt/poudriere the debugging variables must be specified in poudriere’s make.conf and not in /etc/make.conf. Refer to ports-mgmt/poudriere documentation for details. |
Please refer to the debugging information in the Developer’s Handbook for more details about the debugging tools available.
Last modified on: September 20, 2024 by Fernando Apesteguía