You’ve decided to ignore the OpenBSD team’s recommendations to use packages, downloaded and extracted the ports tree, found software you need to install from ports, and designated an area for building ports. Now what?
The port directories don’t contain actual source code. When you build a package from a port, the system does the following:
Automatically downloads the appropriate source code from an approved Internet site
Checks the downloaded code for integrity errors
Extracts the code to the build area
Patches the code
Compiles the code
Creates the package
Installs the package (optional)
Additionally, if the port you’re adding has unmet dependencies, the system also handles installing those dependencies.
To make all this happen, just go to the port directory and enter this command:
# make install
You should see the port build the software, create the package, and install the package on your system.
It’s time to dissect a port build and installation. Here’s how to install tcsh
from a port:
# cd /usr/ports/shells/tcsh # make install ===> Verifying specs: c termlib c termlib ===> found c.65.0 termlib.12.1 ===> Checking files for tcsh-6.18.01 >> Fetch ftp://ftp.astron.com/pub/tcsh/tcsh-6.18.01.tar.gz tcsh-6.18.01.tar.gz 100% |**************************************************** | 905 KB 00:00 >> (SHA256) tcsh-6.18.01.tar.gz: OK
The port first checks to see if the software’s required libraries are in place. Building tcsh
requires the termlib
and c
libraries. The port finds termlib
but not a file containing the tcsh
source code on the local system, so the port fetches the code. (When building a port, you should see the system downloading the appropriate source code.) The port then verifies the checksum of the downloaded code. If the port can’t get all of the code, or the checksums don’t match, the build process stops.
Once all necessary source code is downloaded and verified, the build continues with something like this:
… ===> Extracting for tcsh-6.18.01 ===> Patching for tcsh-6.18.01 ===> Configuring for tcsh-6.18.01 Using /usr/ports/pobj/tcsh-6.18.01/config.site (generated) configure: WARNING: unrecognized options: --disable-silent-rules configure: loading site script /usr/ports/pobj/tcsh-6.18.01/config.site checking for a BSD-compatible install… /usr/bin/install -c -o root -g bin checking build system type… i386-unknown-openbsd5.2 checking host system type… i386-unknown-openbsd5.2 …
The port extracts the source code from the compressed file(s), applies any OpenBSD-specific patches, and starts the build process. (Many of you know that configure
is not the same as building software, but not all software requires a configure
step. The port knows what to do.)
The build process will go on for many lines. Building something like OpenOffice can take days and generate hundreds of thousands of lines of output.
If you need to debug a port build failure, those messages that scroll off the top of your screen or terminal window contain all the clues you get. For that reason, I often build ports in a script(1)
session. If you like the idea of keeping build messages around, see the script
man page for details.
Eventually, you should see a message that the build has finished and the port is installing the software.
… ===> Faking installation for tcsh-6.18.01 install -c -s -o root -g bin -m 555 /home/ports/wrkobjdir/tcsh-6.18.01/tcsh-6.18.01/tcsh /home/ports/wrkobjdir/tcsh-6.18.01/fake-i386/usr/local/bin/tcsh install -c -o root -g bin -m 444 /home/ports/wrkobjdir/tcsh-6.18.01/tcsh-6.18.01/tcsh.man /home/ports/wrkobjdir/tcsh-6.18.01/fake-i386/usr/local/man/man1/tcsh.1 install -c -o root -g bin -m 444 /home/ports/wrkobjdir/tcsh-6.18.01/tcsh-6.18.01/nls/C.cat /home/ports/wrkobjdir/tcsh-6.18.01/fake-i386/usr/local/share/nls/C/tcsh.cat …
The port installs the software in a temporary location in the port building directory, but that’s not where we want the software installed! Remember that the ports system builds packages, and then installs from the package. This “fake” installation is for building the package.
… ===> Building package for tcsh-6.18.01 Create /home/ports/pkgrepo/i386/all/tcsh-6.18.01.tgz …
There’s the package, retained in the package repository specified earlier. You might want to grab this file to install on your other machines, or perhaps even share the package repository via NFS.
Now, because we specified make install
on the command line, the port installs the created package.
… ===> Verifying specs: c termlib ===> found c.65.0 termlib.12.1 ===> Installing tcsh-6.18.01 from /home/ports/pkgrepo/i386/all/ … tcsh-6.18.01: ok #
Installing the package requires making some of the same checks as building the package. Yes, the port could not have built the package without those libraries, but the ports system doesn’t assume that the package was built on the local system.
The package build process actually includes several stages, or smaller chunks of build procedure. Each stage performs all the stages before it. The final stage, make install
, calls all of them, which provides several points where you can intervene in the port build process. If you want to make custom changes to a package, you can do it here.
Let’s look at each of the stages called for every port build.
The make fetch
stage gets the source code, or distfiles, for the port. First, it looks in any directories specified by the mk.conf variable $DISTDIR
. If this variable isn’t set, it looks in the directory specified by the shell environment variable $DISTDIR
. If neither variable is set, it looks in /usr/ports/distfiles. If make fetch
finds the distribution files and thinks that they’re the correct version, it hands control to the next requested stage, and the build continues.
If the source code is not on the local machine, make fetch
tries to download it from an Internet site specified in the port’s makefile as MASTER_SITES
. (You can customize download locations, as discussed in Customizing Ports.)
You’ll find the make fetch
command very useful when there are certain times in your day when you can download more easily than other times. For example, I have a T1 to my house,[38] but my employer’s office has roughly 66 times as much bandwidth as I have at home. I can run make fetch
on my laptop while visiting my employer, go home, and build the port in peace. (And the boss thinks I come in because he buys lunch.)
The make checksum
stage verifies that distfiles have not been corrupted, either by the download process or maliciously. OpenBSD includes several different checksums for each distfile, but only checks that the SHA-256 checksum matches the distfile. If the checksum matches, the build proceeds to the next stage. If the checksums do not match, the build immediately aborts. The build will not continue until you find a distfile that matches the checksum.
Not all software developers are conscientious about updating the names of their distfiles when they update their software. For these software packages, the foo-1.0.tgz file the port developer downloaded in the morning might differ from the foo-1.0.tgz file you download later that same day. Perhaps the original software author thought that no one would notice, but the OpenBSD folks would, if only via the logic built into the ports tools. After all, the ports system can’t tell the difference between a source file quietly modified by the software author and a source file quietly modified by an intruder. If you get a distfile that doesn’t match the recorded checksum, try to fetch a matching file by setting the REFETCH
variable to true
.
# make checksum REFETCH=true
Now make
will walk through all the distfile sources listed in the port, downloading them successively in an effort to find a distfile that matches that used by the port developer.
If you are absolutely certain that the file you downloaded is the correct, untampered-with one, but it still doesn’t pass make checksum
, you’re wrong. If you know that you’re wrong, but you really do want to install compromised or damaged software, set the environment variable NO_CHECKSUM=yes
to skip the make checksum
stage.
Skipping the make checksum
stage might be valid for debugging, but it certainly isn’t the way to create a stable, useful, or secure package. You also might invalidate the rest of the port. Perhaps the OpenBSD patches will no longer apply cleanly, the software just won’t run, or you could even be installing a backdoor, inviting scumbags to stash problematic content on your machine. You are utterly on your own if you insist on ignoring a checksum mismatch.
At this point, the ports system gets into recursion. At make prepare
, the port checks for any software needed to build or run the software you’re trying to build. If the port lists any of these dependencies, it checks to see if they are installed. If the dependencies are not installed, this stage kicks off make install
for those required ports. Once all of the required dependencies are installed, this stage ends.
The ports system must extract the source code from the distfile before building the software. Source code is extracted into the directory defined by $WRKOBJDIR
, or in a directory under /usr/ports/pobj/ named after the port. By default, my tcsh
port would extract under /usr/ports/pobj/tcsh, but because I defined a separate location for building software, it’s built under /home/ports/wrkobjdir/tcsh.
Any patches included in the port’s patches directory are applied in the make patch
stage. If the patches all apply correctly, this stage ends. If the patches do not apply correctly, the port fails.
To apply your own patches to the port, or to review the code before compiling it, run make patch
first. Your patches might conflict with the port patches if you apply them first, cause compilation failures, or bring up any number of other problems. By running make patch
first, you get to see the code as OpenBSD can compile it. Anything you break after that is definitely your fault.
Many software packages use a configure
script to prepare themselves for compilation on a specific platform. The make configure
command runs that script. If you want to edit the configure
script, do so before running this stage! If there is no configure
script, the port silently skips this stage.
The make build
stage compiles the fetched, extracted, patched, and configured software. If you type make
in a port directory, the port calls make build
. This stage doesn’t assemble a package; it just performs the compilation and creates the actual program binaries in the port’s work directory.
The make fake
stage installs the software in a subdirectory, laid out exactly as it would be under the root directory. This fake root directory is in the work directory, named fake- with the architecture appended, such as fake-amd64. Everything that will be in the package is installed under this directory, with the same ownership and permissions that it will include in the package.
The make package
stage bundles up the port’s fake installation directory, adds in packaging and installation instructions, and ties it all up in a package exactly like those available on the FTP site. The package will be stored under the PKGREPO directory you defined earlier (or in /usr/ports/packages if you didn’t define one), in a subdirectory organized by architecture, and in further subdirectories organized by available distribution locations.
make package
means that you can build this port on one machine without installing it. You must install the build dependencies to build the port, however.
The make install
stage runs pkg_add(1)
to install the package you compiled.
Some packages require a lot of disk space. The make clean
stage removes all of the build files except the distfile and the completed package.