If you're a typical FreeBSD user, you don't have a background in C
programming. Yet, if you've ever used make world to upgrade your
operating system or issued a make install somewhere within your
ports tree, you've compiled C code.
This article covers some make basics so you have an idea what
is happening behind the scenes. It also examines some of the options you have
available when issuing make commands.
You may be wondering why you should care about C if you have no intention of becoming a C programmer. The reason is simple: most operating systems
(including FreeBSD) are written in C, as are most executable programs. As an
example, use the file command to see the type of third-party
programs installed on your system:
% file /usr/local/bin/* | more
You'll find some Bourne shell scripts and perl scripts, but the rest will be executables compiled from C source code and say something like "ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), for FreeBSD 5.3.0, dynamically linked (uses shared libs), stripped."
Keep in mind that you can run FreeBSD for years without ever typing
make. Simply install the operating system from scratch whenever
you want to upgrade to a new version. Leave the kernel as is. That's right, the
kernel is also written in C, which is why you type make buildkernel
and make installkernel. Don't install the ports collection, and
always install software using pkg_add -r. Think of all the disk
space you'll save, as you'll have no need to install src or
ports.
However, you won't be taking full advantage of the many benefits of an open source operating system--other than the free price tag.
make BasicsOK, so what is make, anyway? According to man
make, it maintains program dependencies. As any C programmer who has
ever worked on a software project can tell you, there can be literally hundreds of source
files, header files, and object files to compile and link in order to generate
an executable program. make's job is to ensure that everything happens
in the correct order.
In order for make to do its thing, it reads a Makefile
in the same directory from which you run the make command. For
example, say I try this in my home directory:
% cd
% make
make: no target to make.
That message means that there isn't a file called Makefile in the directory. However, suppose I issue the same command (as superuser) from somewhere in the ports tree:
# cd /usr/ports/shells/bash
# make
make will go out on the internet looking for some source code
to compile. This makes sense, as you need C source code in order to
make this program.
How did make know to go to the internet looking for that
source code, and more importantly, how did it know which specific FTP site
contained the source code it needed? If you guessed that the instructions were
in a Makefile in that directory, you are correct:
# ls /usr/ports/shells/bash
Makefile files pkg-descr pkg-plist
distinfo pkg-deinstall pkg-install
If you read through that Makefile, you'll find a
MASTER_SITES variable that lists the URLs to sites containing the
required source code.
Note: In case you're wondering where that downloaded source ends up, the
Makefile copies it to /usr/ports/distfiles/ as a tarball. It
then extracts this tarball into a subdirectory of your current directory called
work. Typing make install clean will delete
work--don't type clean if you want to keep the
work directory.
You don't have to be that brave to wade through a port's Makefile,
as most of the uppercase variables have explanatory names. If you come across
one that isn't self-explanatory or want a bird's-eye view of what each variable
does, check out the make file that explains the format of port
Makefiles:
% more /usr/ports/Mk/bsd.port.mk
Knowing the names of some of these variables can be useful to you, not just
make. For example, I can search for the MAN variable
to determine which man pages a port will install:
% grep MAN /usr/ports/mail/postfix/Makefile
MAN1= mailq.1 newaliases.1 postalias.1 postcat.1 postconf.1 postdrop.1 \
MAN5= access.5 aliases.5 canonical.5 cidr_table.5 ldap_table.5 \
MAN8= bounce.8 cleanup.8 defer.8 error.8 flush.8 lmtp.8 local.8
The MAN variable uses a number to represent the section of the
manual. By using grep to search for this variable, I know that
this port will install six man pages into section 1, five into section 5, and
seven into section 8. Looks like I'll be doing a lot of reading if I install
this port!
make TargetsBesides using grep to glean information out of a
Makefile, you can also take advantage of make targets.
Target is the proper term for the action word(s) you type after
make. For example, you've probably used the install
and clean targets when building a port. Not surprisingly,
/usr/ports/Mk/bsd.port.mk contains a list of all the targets supported
when compiling a port. You can find this list by using / to search
for the Default targets section once you've opened this file in a
pager:
% more /usr/ports/Mk/bsd.port.mk
/Default targets
However, you may find it easier to read man ports, as it further
explains the common targets.
If you've never done anything fancier than make install, you
should practice using each of the targets on a test system, as they may not
necessarily work the way you think they would after reading the
descriptions.
For example, try running make configure instead of make
install from /usr/ports/shells/bash. At first glance, this
looks like a normal compile, as make goes out looking for source
code, extracts it, and configures it for your system. Note that it doesn't
actually build the code or install the program,
though.
If you read man ports carefully, you'll see that the usual
make install is really a whole bunch of targets run in this order:
config, fetch, checksum,
depends, extract, patch,
configure, build, and finally install.
If you specify any other target, make will start at
config and run every target up to and including the specified
target. So, make configure does everything from make
config to make configure.
Next, run make configure from /usr/ports/mail/postfix.
The make process will begin, and depending upon the speed of your
internet connection, some moments later you'll see a dialog menu
box where you can pick and choose which options to pass to the configuration
script.
This may have bitten you before: you type make install, leave
your computer to attend to something else, and come back an hour later only to
find not a newly compiled program but instead a dialog menu waiting for your input. Wanna know a secret? The ports that pop up such menus always
have a scripts directory containing a dialog script
called configure. If you see such a directory when you cd
into a ports skeleton, stick around, as it will ask you for some interaction
before the build begins.
|
make configYou may be wondering what the difference is between make
configure and make config. I've shown so far that
make configure runs after several targets and may or may not
require the user to interact with a dialog script.
In contrast, the config target is the first to run and always
uses a dialog script to allow you to configure
OPTIONS. Note that OPTIONS is uppercase on purpose;
it refers to a make variable.
For example:
# cd /usr/ports/multimedia/xmms
# make config
===> No options to configure
That shouldn't be surprising, as the Makefile doesn't use any OPTIONS:
# grep -w OPTIONS /usr/ports/multimedia/xmms/Makefile
#
However, this Makefile does use this variable:
# grep OPTIONS /usr/ports/graphics/kdegraphics3/Makefile
OPTIONS= IMLIB "Build Kuickshow, a fast and versatile image viewer" off \
Note that the trailing \ indicates that there are more options;
to see more, change grep to grep -A 5 to see the five
lines starting at (After) OPTIONS.
Now try:
# cd /usr/ports/graphics/kdegraphics3
# make config
A dialog script immediately opens, displaying all of the
possible options. Those enabled in the Makefile will be on by default,
whereas those tagged as off will not. Once you make your own selections and tab
over to OK, you'll receive your prompt back, as make config is
the first and only target to run.
Did you know that /var/db/ports/ saves your selected
OPTIONS for you?
# more /var/db/ports/kdegraphics/options
# This file is auto-generated by 'make config'.
# No user-servicable parts inside!
# Options for kdegraphics-3.3.2_2
_OPTIONS_READ=kdegraphics-3.3.2_2
WITHOUT_IMLIB=true
WITHOUT_GPHOTO2=true
WITHOUT_SANE=true
You can also view your selections from within the port's directory using the
showconfig target:
# pwd
/usr/ports/graphics/kdegraphics3
# make showconfig
===> The following configuration options are set for kdegraphics-3.3.2_2:
IMLIB=off "Build Kuickshow, a fast and versatile image viewer"
GPHOTO2=off "Enable support for digital cameras"
SANE=off "Build Kooka, a SANE scanner frontend for KDE"
Should you change your mind, you can always rerun make config.
Alternatively, remove the config options using:
# make rmconfig
===> Removing user-configured options for kdegraphics-3.3.2_2
# more /var/db/ports/kdegraphics/options
/var/db/ports/kdegraphics/options: No such file or directory
Quick, what directory are you in when you issue a make command
to upgrade the operating system or build a new kernel? There has to be a
Makefile in that directory, or else your make command
would fail. Take a look at it:
% more /usr/src/Makefile
This is an interesting Makefile that starts off mentioning targets
you've probably used before, such as buildworld,
buildkernel, installkernel, and
installworld. However, search for Targets and you'll
see this section:
# Targets that begin with underscore are internal targets intended for
# developer convenience only. They are intentionally not documented and
# completely subject to change without notice.
#
TGTS= all all-man buildkernel buildworld checkdpadd clean \
cleandepend cleandir depend distribute distributeworld everything \
hierarchy install installcheck installkernel installkernel.debug\
reinstallkernel reinstallkernel.debug installworld \
kernel-toolchain libraries lint maninstall \
obj objlink regress rerelease tags toolchain update \
_worldtmp _legacy _bootstrap-tools _cleanobj _obj \
_build-tools _cross-tools _includes _libraries _depend
Note: It's one thing to try new make targets in the ports
tree--the worst that can happen is you'll end up installing an application.
However, if you have the urge to deviate from the targets described in the
Handbook for safely upgrading the operating system or a kernel, practice on
a test system that doesn't contain any data you'd miss should something go
terribly wrong.
The rest of the Makefile describes the documented targets. There
are a few interesting things to note. The
Handbook cautions against using make world. This
Makefile explains further:
#
# world
#
# Attempt to rebuild and reinstall everything. This target is not to be
# used for upgrading an existing FreeBSD system, because the kernel is
# not included. One can argue that this target doesn't build everything
# then.
#
world:
@echo "WARNING: make world will overwrite your existing FreeBSD"
@echo "installation without also building and installing a new"
@echo "kernel. This can be dangerous. Please read the handbook,"
@echo "'Rebuilding world', for how to upgrade your system."
@echo "Define DESTDIR to where you want to install FreeBSD,"
@echo "including /, to override this warning and proceed as usual."
@echo "You may get the historical 'make world' behavior by defining"
@echo "HISTORICAL_MAKE_WORLD. You should understand the implications"
@echo "before doing this."
@echo ""
@echo "Bailing out now..."
This file also indicates that make kernel is really make
buildkernel followed by make installkernel. That means that
you could replace:
# make buildkernel KERNCONF=NEW && make installkernel KERNCONF=NEW
with:
# make kernel KERNCONF=NEW
Note that the Makefile assumes GENERIC unless you
specify another kernel with KERNCONF.
The last target I want to mention is make update. If you try
typing that as is, you'll just receive your prompt back, meaning nothing
happened. This is because this target reads the file /etc/make.conf to
see exactly what you'd like to update.
On my test system, I already had cvsup up and running and had
created a sup file in /root/cvs-supfile. So, I added these
lines to /etc/make.conf:
SUP_UPDATE= yes
SUP= /usr/local/bin/cvsup
SUPFLAGS= -g -L 2
SUPFILE= /root/cvs-supfile
Note: In order for this to work, you must have cvsup-without-gui installed and have
configured a SUPFILE at the specified location. If you've installed cvsup-without-gui but haven't yet
created a SUPFILE, replace that SUPFILE line with
these:
SUPHOST= cvsup.ca.freebsd.org
SUPFILE= /usr/share/examples/cvsup/standard-supfile
PORTSSUPFILE= /usr/share/examples/cvsup/ports-supfile
DOCSUPFILE= /usr/share/examples/cvsup/doc-supfile
When
filling in SUPHOST=, please choose a mirror geographically close
to you. Also, review the three files in /usr/share/examples/cvsup
to pick and choose which parts of the operating system, ports, and docs you
wish to update.
When you've finished, run make update from /usr/src to
update the specified sources.
Perhaps you've wondered how some people on the mailing lists knew about
commands that went beyond make install. Today you found out what
files they read to learn that information. Just remember, if you want to try
out some new make targets for yourself, use a testing system and
back up any data that is important to you first.
Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.
|
Related Reading Managing Projects with GNU Make |
Return to the BSD DevCenter.
Copyright © 2009 O'Reilly Media, Inc.