Here I'm republishing an old blog post of mine originally from October 2017. The article has been slightly improved.

Please mind that there have been some changes in FreeBSD after the article was written. Two important ones that you should be aware of are: The introduction of so-called "flavored ports" (I covered these when revisiting the topic two years after writing this one) and the transition from Subversion to Git.

FreeBSD: Building software from ports (2/2)

My previous post discussed what ports are, where they can be found on FreeBSD and what the files of which a port is composed of look like. This post will now detail how to use ports to build software on FreeBSD (the other BSDs have ports trees that work somewhat similar but are not identical. There are important differences!).

FreeBSD: Building software from ports (1/2)

Packages and ports: A word of warning

The ports system works hand in hand with FreeBSD's package manager pkg(8). It makes little difference if some software on your machine was installed via a package or directly from ports - packages are in fact actually built from ports! Still it is not really recommended to mix packages and ports. In past times it was strongly discouraged. Things have changed since then. I've done it a lot - and mostly got away with it. Don't rely on it, though, especially if you're new to the whole topic. Feel free to do it on a test system and be completely happy - or face subtle and annoying breakage. You cannot know up front.

What's the deal here? Modern software is a complex thing. Most programs rely on other programs or external libraries. A lot of programs can be configured at run time in certain ways. There are however decisions about program functionality that have to be made at compile time. The ports system allows you to build software with compile-time options other than the default. Pre-compiled packages have no chance to know that you choose to deactivate an option when you built a library yourself that they make use of. They assume that this feature is present (it was available on the system the package was built on after all!). And what can one poor program do in that case? Crash, explode, malfunction... A lot of things.

And then there's the problem of mixing versions which can lead to all kinds of fun. If you stick with either ports _or_ packages, you always have a consistent system with versions that are known to play together well (as long as the maintainers do their job well - we're all humans and errors do occur).

Just keep that in mind when thinking about mixing programs installed from packages and ports on one system. You can do that. But it doesn't mean you should. Enabling more options is generally safer than removing ones set by default. It can still have consequences. This is Unix though: Do whatever you see fit - and claim the responsibility. Your choice.

Most basic ports building

Building a software from ports is extremely easy. Go to the directory of a port and type _make_. Yes, that's all! Let's assume the port has no unsatisfied dependencies. The ports system will then check to see if the source code tarball is present in _/usr/ports/distfiles_. If it isn't, it will automatically download it. Then it extracts the source code, prepares everything for the compilation and compiles it.

Building the "pkg" port (PNG)

On my fresh example system I build the pkg manager from ports first - it's needed for every other port anyway. Once everything has finished I get my shell prompt back.

Building of Pkg completed (PNG)

Actually installing the freshly-built program is just as easy: Just type _make install_ and it happens.

Installing the application (PNG)

That's it, pkg is now installed. We're basically done with that port. However there's still the "work" directory left over from the building process. To tidy up our port's directory we can issue _make clean_.

Cleaning up after the build (PNG)

Dependency handling

On to a just slightly more complex example. I want to build and install an old version of the _Lua_ interpreter which depends on another port, _libedit_. Of course I could build _devel/libedit_ first and then _lang/lua51_. In that case it wouldn't be so bad. But if you think of larger programs with hundreds of dependencies that approach would be a nightmare.

So what to do about it? Well, nothing actually. The ports system takes care of it automatically! Just have it build Lua and it will figure out that it has to build the dependency first.

Building, installing and cleaning up in one command (PNG)

The parameters to make that we used above are called "make targets", BTW, and can be combined. That means it's perfectly fine to issue _make install clean_ together as you can see in the picture above.

Dependencies are handled automatically (PNG)

The _clean_ make target is also applied to all ports that were built as a dependency for the current port. Things like this make ports very convenient to use.

More on make and targets

Make targets can depend on other make targets. When you run _make install_ these are the targets that are actually run:

If you type _make checksum_ for example, all targets up to and including that one will run (that is _config_, _fetch_ and _checksum_ in that case). Running just _make_ without any target will assume the default target which is equivalent to _make build_.

Also make will take an argument to look for the Makefile in another directory if you wish. So instead of doing e.g. this:

# cd /usr/ports/archivers/bzip2
# make install clean
# cd -

you could also simply do this:

# make -C /usr/ports/archivers/bzip2 install clean

You're in control: Ports options

So far it's all nice and well but there's no real advantage to using ports instead of packages. May I introduce ports options? Let's say you we want to build BASH. If you issue _make_ in /usr/ports/shells/bash, this is what happens:

Build options for BASH (PNG)

The disftifle fo the port _ports-mgmt/dialog4ports_ is fetched and the program installed. It's so small that you might miss it but it's quite important. It's needed to display the menu in the picture above which lets you set various options for the port.

You can now e.g. choose to not install the documentation if you're short on space on a small or embedded system (sure, you wouldn't actually compile on such a system, but that's only an example, right?). If you don't want BASH to support any foreign languages, deselect _NLS_. In case you feel that BASH's built-in help is useless (did you ever issue the _help_ command when you ran BASH?), you can cut that feature. Things like that.

If you see the option configuration for a port the first time, you see the default configuration. In general it's a good idea to leave options alone if you're in doubt what they do (do a little research if you have the time). Of course you're also free to experiment with them. It's your system after all.

Once you're happy, accept your selection and the source tarball is being fetched, extracted, etc. You know the score.

Build options for bison (PNG)

But what's that? Another configuration menu (for bison)? And another (m4) and another (texinfo), etc... It's 8 menus for a rather basic program like BASH! And worse: The building process will run and build dependencies and when a port with options is reached, the process is interrupted and presents the options to the user.

Now imagine you're building a whole graphical desktop like e.g. MATE... Currently even the basic desktop would build no less that _338 dependency packages_ on a fresh system! And there's quite a few ports on the list which build rather heavy software that takes it's time compiling. It would totally make sense to let it build over night or at least not require you to keep staring at the screen, waiting for the next options selection to confirm, right?

Recursive operations

Exactly that's why _recursive operations_ are supported by the ports system. The standard make target that was implicitly run to open the options dialog is _make config_. The recursive option which would run the same on each and every port that's listed as a dependency for the current port is _make config-recursive_.

If you want to build MATE as mentioned in the previous example, that would start a true marathon of options for you to configure. However it's still a lot better to be able to do this up front so that the build process can run uninterruptedly afterwards.

Oh, and don't be surprised if you went through it all only to find that _still_ another configuration dialog pops up later! Why? Most likely you enabled an option on some package that made it depend on another package that's not a dependency by default. And that package may need to have its options configured, too. So if you changed any options it makes sense to run _make config-recursive_ again until no more new option dialog windows are displayed!

Recursively fetching distfiles for security/sudo (PNG)

You can also do _make fetch-recursive_ to fetch the distfiles for the current port and all dependencies. Again: Keep in mind that enabling more options may lead to new dependencies. If you want to make sure that you have all the distfiles, you might want to run _make fetch-recursive_ a second time after changing ports options.

Other things to know

Wonder where the all the options are saved? They are stored in text files in _/var/db/ports/category_portname_. But there's no need to edit or delete them; if you want to get rid of them, there's _make rmconfig_ to do that. Also _make rmconfig-recursive_ exists if you feel like blowing away a huge amount of them.

Ports options in /var/db/ports (PNG)

Another thing that comes in handy is _make build-depends-list_ which will show you a list of ports that will be built as build dependencies for your current port. If you want to see the runtime dependencies you would use _make run-depends-list_. And then there's also _make all-depends-list_ which will show you each and every port that would be installed if you chose to build the current port.

Showing port dependencies (PNG)

You should also know that you can deinstall a port by using _make deinstall_. Yes, it is also possible to remove the package using _pkg delete_ but that will lead to a problem. The ports infrastructure keeps track of installed ports separately and pkg does not know anything about this. So even if your package is removed, the Ports infrastructure will insist that it is still installed and there's something very wrong with your system!

Now what to do if you have that case? Use _make reinstall_ to install the package again even though ports thinks that it's already installed.

More on ports?

To be honest, there's quite a bit more to ports than I could cover here. You may want to _man 7 ports_ to see what other targets are available and what they do. Also we haven't even touched how to keep your system updated when using ports and how to configure certain options system-wide!

The ports infrastructure is a great means of installing customized programs on your system. It's quite easy to use as you've seen. But things can be made even easier - which is why there are helper tools available. I will write a follow-up article covering those (not the next one, though). But for now enjoy all of those new possibilities with software on your FreeBSD machines!

BACK TO 2017 OVERVIEW