Table of Contents

FreeBSD Ports: Passing Optional Arguments to make

FreeBSD has a very neat 'ports' system, which lets you install software easily.

If the ports tree is installed, all you have to do is:

cd /usr/ports/ftp/proftpd
make
make install
make clean

That will download the software you've chosen (proftpd in this case), configure it, make it, install it, and then cleanup. You can even shorten it to one command if you want to be brave:

make install clean

Non-Default Options

What if you don't want the default options for your particular install? There are a number of ways to customize your install:

make config

If you type make config, and the port supports it (not all ports do), you'll get a menu with the various options you can use for that port. For example, for proftpd, you'll see a bunch of options such as MYSQL (enable MySQL support), QUOTA (enable quota management), and IPV6 (enable IPv6 support). Check the ones you want, uncheck the ones you don't, and you're off to the races.

To see the current config, type make showconfig, and reset the config to the default, type make rmconfig.

Using make's -D command line argument

If you look at the makefile for a given port, you'll see most of the options are included if some variable (such as WITH_RADIUS or WITH_IPV6) is defined. For example, here is a snippet from the proftpd ports makefile:

.if defined(WITH_RADIUS)
MODULES:=${MODULES}:mod_radius
.endif

The -D command line switch lets you define a variable to be 1 (thus making it defined). If you do:

make -DWITH_RADIUS

you'll trigger the if statement in the makefile, and thus proftpd will get compiled with Radius support. You can use multiple -D options, e.g.

make -DWITH_RADIUS -DWITH_IPV6 -DWITH_BAN

To figure out what options are available, look at the documentation (or just look at the makefile!)

Setting a variable manually: VARIABLE=VALUE

make also lets you set variables manually via the command line, which is useful if you need to set a variable to a specific value:

make WITH_RADIUS=1 LOCALBASE=/usr/local

Setting WITH_RADIUS=1 does almost, but not quite, the same thing as -DWITH_RADIUS. To understand the difference, you need to understand make's idea of 'variable context'. Basically, a variable can exist in any of four different levels (or 'contexts'); if the same variable is defined in two contents, the one with the higher (bigger) number on the following list will override the one with the lower number. The contexts are: 1. Environment variables: Variables defined as part of make's environment. 2. Global variables: Variables defined in the makefile or in included makefiles. 3. Command line variables: Variables defined as part of the command line. 4. Local variables: Variables that are defined specific to a certain target.

If you look at the man page for make, you'll see it says:

-D variable
    Define variable to be 1, in the global context.
variable=value
    Set the value of the variable variable to value.

That part about in the global context is key. If you set a variable with -D, the makefile can change or overwrite it, because it is in the same context as variables defined in the makefile (#2 on the above list). But, if you define it to the exact same value with VARIABLE=1, the makefile cannot change it, because it has been defined in the 'command line context' (#3), and is thus higher than #2.

This is a subtle difference, but has caused no end of frustration in the past, so keep it in mind.

Setting a variable in the environment

-D can only set a variable to a value of 1. So how do you set a variable to a specific value (e.g. /usr/local) in the global context (and thus let the makefile change it)? I'm not aware of a way to set a variable in the global context without altering the makefile, but you can set an environment variable, which is a lower context, and then let make read it. So you might do:

LOCALBASE=/usr/local
export LOCALBASE
make
make install
LOCALBASE=

This isn't ideal, but certainly works. Comments welcome.