Last Updated: 21 Nov 2020
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.
Discussion