development(7)

NAME

development - introduction to development with the FreeBSD
codebase

DESCRIPTION

This manual page describes how an ordinary sysop, UNIX ad
min, or developer can, without any special permission, obtain, maintain,
and modify
the FreeBSD codebase as well as how to maintain a master
build which can
then be exported to other machines in your network. This
manual page is
targeted to system operators, programmers, and developers.
Please note that what is being described here is based on a
complete
FreeBSD environment, not just the FreeBSD kernel. The meth
ods described
here are as applicable to production installations as it is
to development environments. You need a good 12-17GB of disk space on
one machine
to make this work conveniently.

SETTING UP THE ENVIRONMENT ON THE MASTER SERVER

Your master server should always run a stable, production
version of the
FreeBSD operating system. This does not prevent you from
doing -CURRENT
builds or development. The last thing you want to do is to
run an unstable environment on your master server which could lead to a
situation
where you lose the environment and/or cannot recover from a
mistake.
Create a huge partition called /FreeBSD. 8-12GB is recom
mended. This
partition will contain nearly all the development environ
ment, including
the CVS tree, broken-out source, and possibly even object
files. You are
going to export this partition to your other machines via a
READ-ONLY NFS
export so do not mix it with other more security-sensitive
partitions.
You have to make a choice in regards to /usr/obj. You can
put /usr/obj
in /FreeBSD or you can make /usr/obj its own partition. I
recommend making it a separate partition for several reasons. First, as
a safety measure since this partition is written to a great deal. Sec
ond, because
you typically do not have to back it up. Third, because it
makes it far
easier to mix and match the development environments which
are described
later in this document. I recommend a /usr/obj partition of
at least
5GB.
On the master server, use cvsup(1) (ports/net/cvsup) to au
tomatically
pull down and maintain the FreeBSD CVS archive once a day.
The first
pull will take a long time, it is several gigabytes, but
once you have
it, the daily syncs will be quite small.

mkdir /FreeBSD/FreeBSD-CVS
rm -rf /home/ncvs
ln -s /FreeBSD/FreeBSD-CVS /home/ncvs
The cron(8) job should look something like this (please ran
domize the
time of day!). Note that you can use the cvsup(1) configu
ration file
example directly from /usr/share/examples without modifica
tion by supplying appropriate arguments to cvsup(1).

33 6 * * * /usr/local/bin/cvsup -g -r 20 -L 2 -h
cvsup.freebsd.org /usr/share/examples/cvsup/cvs-supfile
Run the cvsup(1) manually the first time to pull down the
archive. It
could take all day depending on how fast your connection is!
You will
run all cvsup(1) and cvs(1) operations as ``root'' and you
need to set up
a ~/.cvsrc (/root/.cvsrc) file, as shown below, for proper
cvs(1) operation. Using ~/.cvsrc to specify cvs(1) defaults is an ex
cellent way to
``file and forget'', but you should never forget that you
put them in
there.

# cvs -q
diff -u
update -Pd
checkout -P
Now use cvs(1) to check out a -STABLE source tree and a
-CURRENT source
tree, as well as ports and docs, to create your initial
source environment. Keeping the broken-out source and ports in /FreeBSD
allows you to
export it to other machines via read-only NFS. This also
means you only
need to edit/maintain files in one place and all your
clients automatically pick up the changes.

mkdir /FreeBSD/FreeBSD-4.x
mkdir /FreeBSD/FreeBSD-current
cd /FreeBSD/FreeBSD-4.x
cvs -d /home/ncvs checkout -rRELENG_4 src
cd /FreeBSD/FreeBSD-current
cvs -d /home/ncvs checkout src
cvs -d /home/ncvs checkout ports
cvs -d /home/ncvs checkout doc
Now create a softlink for /usr/src and /usr/src2. On the
main server I
always point /usr/src at -STABLE and /usr/src2 at -CURRENT.
On client
machines I usually do not have a /usr/src2 and I make
/usr/src point at
whatever version of FreeBSD the client box is intended to
run.

cd /usr
rm -rf src src2
ln -s /FreeBSD/FreeBSD-4.x/src src (could be -CUR
RENT on a client)
ln -s /FreeBSD/FreeBSD-current/src src2 (MASTER SERVER
ONLY)
Now you have to make a choice for /usr/obj. Well, hopefully
you made it
already and chose the partition method. If you chose poorly
you probably
intend to put it in /FreeBSD and, if so, this is what you
want to do:

(ONLY IF YOU MADE A POOR CHOICE AND PUT /usr/obj in
/FreeBSD!)
mkdir /FreeBSD/obj
cd /usr
rm -rf obj
ln -s /FreeBSD/obj obj
Alternatively you may chose simply to leave /usr/obj in
/usr. If your
/usr is large enough this will work, but I do not recommend
it for safety
reasons (/usr/obj is constantly being modified, /usr is
not).
Note that exporting /usr/obj via read-only NFS to your other
boxes will
allow you to build on your main server and install from your
other boxes.
If you also want to do builds on some or all of the clients
you can simply have /usr/obj be a local directory on those clients.
You should
never export /usr/obj read-write, it will lead to all sorts
of problems
and issues down the line and presents a security problem as
well. It is
far easier to do builds on the master server and then only
do installs on
the clients.
I usually maintain my ports tree via CVS. It is sitting
right there in
the master CVS archive and I have even told you to check it
out (see
above). With some fancy softlinks you can make the ports
tree available
both on your master server and on all of your other ma
chines. Note that
the ports tree exists only on the HEAD CVS branch, so its
always -CURRENT
even on a -STABLE box. This is what you do:

(THESE COMMANDS ON THE MASTER SERVER AND ON ALL CLIENTS)
cd /usr
rm -rf ports
ln -s /FreeBSD/FreeBSD-current/ports ports
cd /usr/ports (this pushes in
to the softlink)
rm -rf distfiles (ON MASTER SERV
ER ONLY)
ln -s /usr/ports.distfiles distfiles (ON MASTER SERV
ER ONLY)
mkdir /usr/ports.distfiles
mkdir /usr/ports.workdir
Since /usr/ports is softlinked into what will be read-only
on all of your
clients, you have to tell the ports system to use a differ
ent working
directory to hold ports builds. You want to add a line to
your
make.conf(5) file on the master server and on all your
clients:

WRKDIRPREFIX=/usr/ports.workdir
You should try to make the directory you use for the ports
working directory as well as the directory used to hold distfiles consis
tent across
all of your machines. If there is not enough room in
/usr/ports.distfiles and /usr/ports.workdir I usually make
those softlinks (since this is on /usr these are per-machine) to where
the distfiles and working space really are.

EXPORTING VIA NFS FROM THE MASTER SERVER

The master server needs to export /FreeBSD and /usr/obj via
NFS so all
the rest of your machines can get at them. I strongly rec
ommend using a
read-only export for both security and safety. The environ
ment I am
describing in this manual page is designed primarily around
read-only NFS
exports. Your exports file on the master server should con
tain the following lines:

/FreeBSD -ro -alldirs -maproot=root: -network YOURLAN
-mask YOURLANMASK
/usr/obj -ro -alldirs -maproot=root: -network YOURLAN
-mask YOURLANMASK
Of course, NFS server operations must also be configured on
that machine.
This is typically done via your /etc/rc.conf:

nfs_server_enable="YES"
nfs_server_flags="-u -t -n 4"

THE CLIENT ENVIRONMENT

All of your client machines can import the development/build
environment
directory simply by NFS mounting /FreeBSD and /usr/obj from
the master
server. A typical /etc/fstab entry on your client machines
will be something like this:

masterserver:/FreeBSD /FreeBSD nfs ro,bg
0 0
masterserver:/usr/obj /usr/obj nfs ro,bg
0 0
And, of course, you should configure the client for NFS
client operations
via /etc/rc.conf. In particular, this will turn on nf
siod(8) which will
improve client-side NFS performance:

nfs_client_enable="YES"
Each client should create softlinks for /usr/ports and
/usr/src that
point into the NFS-mounted environment. If a particular
client is running -CURRENT, /usr/src should be a softlink to
/FreeBSD/FreeBSD-current/src. If it is running -STABLE,
/usr/src should
be a softlink to /FreeBSD/FreeBSD-4.x/src. I do not usually
create a
/usr/src2 softlink on clients, that is used as a convenient
shortcut when
working on the source code on the master server only and
could create
massive confusion (of the human variety) on a client.

(ON EACH CLIENT)
cd /usr
rm -rf ports src
ln -s /FreeBSD/FreeBSD-current/ports ports
ln -s /FreeBSD/FreeBSD-XXX/src src
Do not forget to create the working directories so you can
build ports,
as previously described. If these are not good locations,
make them
softlinks to the correct location. Remember that
/usr/ports/distfiles is
exported by the master server and is therefore going to
point to the same
place (typically /usr/ports.distfiles) on every machine.

mkdir /usr/ports.distfiles
mkdir /usr/ports.workdir

BUILDING KERNELS

Here is how you build a -STABLE kernel (on your main devel
opment box).
If you want to create a custom kernel, copy GENERIC to
KERNELNAME and
then edit it before configuring and building. The kernel
configuration
file lives in /usr/src/sys/i386/conf/KERNELNAME.

cd /usr/src
make buildkernel KERNCONF=KERNELNAME
WARNING! If you are familiar with the old config/cd/make
method of building a -STABLE kernel, note that the config(8) method will
put the build
environment in /usr/src/sys/i386/compile/KERNELNAME instead
of in
/usr/obj.
Building a -CURRENT kernel

cd /usr/src2 (on the master server)
make buildkernel KERNCONF=KERNELNAME

INSTALLING KERNELS

Installing a -STABLE kernel (typically done on a client, on
ly do this on
your main development server if you want to install a new
kernel for your
main development server):

cd /usr/src
make installkernel KERNCONF=KERNELNAME
If you are using the older config/cd/make build mechanism
for -STABLE,
you would install using:

cd /usr/src/sys/i386/compile/KERNELNAME
make install
Installing a -CURRENT kernel (typically done only on a
client)

(remember /usr/src is pointing to the client's specific
environment)
cd /usr/src
make installkernel KERNCONF=KERNELNAME

BUILDING THE WORLD

This environment is designed such that you do all builds on
the master
server, and then install from each client. You can do
builds on a client
only if /usr/obj is local to that client. Building the
world is easy:

cd /usr/src
make buildworld
If you are on the master server you are running in a -STABLE
environment,
but that does not prevent you from building the -CURRENT
world. Just
cd(1) into the appropriate source directory and you are set.
Do not
accidentally install it on your master server though!

cd /usr/src2
make buildworld

INSTALLING THE WORLD

You can build on your main development server and install on
clients.
The main development server must export /FreeBSD and
/usr/obj via readonly NFS to the clients.
NOTE!!! If /usr/obj is a softlink on the master server, it
must also be
the EXACT SAME softlink on each client. If /usr/obj is a
directory in
/usr or a mount point on the master server, then it must be
(interchangeably) a directory in /usr or a mount point on each client.
This is
because the absolute paths are expected to be the same when
building the
world as when installing it, and you generally build it on
your main
development box and install it from a client. If you do not
set up
/usr/obj properly you will not be able to build on machine
and install on
another.

(ON THE CLIENT)
(remember /usr/src is pointing to the client's specific
environment)
cd /usr/src
make installworld
WARNING! If builds work on the master server but installs do
not work
from the clients, for example you try to install and the
client complains
that the install tried to write into the read-only /usr/obj,
then it is
likely that the make.conf(5) file on the client does not
match the one on
the master server closely enough and the install is trying
to install
something that was not built.

DOING DEVELOPMENT ON A CLIENT (NOT JUST INSTALLING)

Developers often want to run buildkernel's or buildworld's
on client
boxes simply to life-test the box. You do this in the same
manner that
you buildkernel and buildworld on your master server. All
you have to do
is make sure that /usr/obj is pointing to local storage. If
you followed
my advise and made /usr/obj its own partition on the master
server, then
it is typically going to be an NFS mount on the client.
Simply unmounting /usr/obj will leave you with a /usr/obj that is a subdi
rectory in
/usr which is typically local to the client. You can then
do builds to
your heart's content!

MAINTAINING A LOCAL BRANCH

I have described how to maintain two versions of the source
tree, a stable version in /FreeBSD/FreeBSD-4.x and a current version in /FreeBSD/FreeBSD-current. There is absolutely nothing pre
venting you
from breaking out other versions of the source tree into
/FreeBSD/XXX.
In fact, my /FreeBSD partition also contains OpenBSD, NetB
SD, and various
flavors of Linux. You may not necessarily be able to build
non-FreeBSD
operating systems on your master server, but being able to
collect and
manage source distributions from a central server is a very
useful thing
to be able to do and you can certainly export to machines
which can build
those other operating systems.
Many developers choose to maintain a local branch of FreeBSD
to test
patches or build a custom distribution. This can be done
with CVS or
another source code management system (SubVersion, Perforce,
BitKeeper)
with its own repository. Since the main FreeBSD tree is
based on CVS,
the former is convenient.
First, you need to modify your cvsup(1) environment to avoid
it modifying
the local changes you have committed to the repository. It
is important
to remove the delete keyword from your supfile and to add
the CVSROOT
subdirectory to your refuse file. For more information, see
cvsup(1).
The FreeBSD version of cvs(1) examines a custom environmen
tal variable,
CVS_LOCAL_BRANCH_NUM, which specifies an integer to use when
doing a
cvs(1) tag/rtag. Set this number to something high (say
1000) to avoid
colliding with potential future branches of the main reposi
tory. For
example, branching a file with version 1.4 produces
1.4.1000. Future
commits to this branch will produce revisions 1.4.1000.1,
1.4.1000.2,
etc.
To fork your local branch, do:

cvs rtag -r RELENG_4 -b LOCAL_RELENG_4 src
After this, you can check out a copy from your local reposi
tory using the
new tag and begin making changes and committing them. For
more information on using CVS, see cvs(1).
WARNING! The cvsup(1) utility may blow away changes made on
a local
branch in some situations. This has been reported to occur
when the master CVS repository is directly manipulated or an RCS file is
changed. At
this point, cvsup(1) notices that the client and server have
entirely
different RCS files, so it does a full replace instead of
trying to send
just deltas. Ideally this situation should never arise, but
in the real
world it happens all the time.
While this is the only scenario where the problem should
crop up, there
have been some suspicious-sounding reports of CVS_LO
CAL_BRANCH_NUM lossage that cannot be explained by this alone. Bottom line
is, if you
value your local branch then you should back it up before
every update.

UPDATING VIA CVS

The advantage of using cvsup(1) to maintain an updated copy
of the CVS
repository instead of using it to maintain source trees di
rectly is that
you can then pick and choose when you bring your source tree
(or pieces
of your source tree) up to date. By using a cron(8) job to
maintain an
updated CVS repository, you can update your source tree at
any time without any network cost as follows:

(on the main development server)
cd /usr/src
cvs -d /home/ncvs update
cd /usr/src2
cvs -d /home/ncvs update
cd /usr/ports
cvs -d /home/ncvs update
It is that simple, and since you are exporting the whole lot
to your
clients, your clients have immediate visibility into the up
dated source.
This is a good time to also remind you that most of the
cvs(1) operations
you do will be done as ``root'', and that certain options
are required
for CVS to operate properly on the FreeBSD repository. For
example, -Pd
is necessary when running cvs update. These options are
typically placed
in your ~/.cvsrc (as already described) so you do not have
to respecify
them every time you run a cvs(1) command. Maintaining the
CVS repository
also gives you far more flexibility in regards to breaking
out multiple
versions of the source tree. It is a good idea to give your
/FreeBSD
partition a lot of space (I recommend 8-12GB) precisely for
that reason.
If you can make it 15GB I would do it.
I generally do not cvs update via a cron(8) job. This is
because I generally want the source to not change out from under me when
I am developing code. Instead I manually update the source every so of
ten... when I
feel it is a good time. My recommendation is to only keep
the CVS repository synchronized via cron(8).

SEE ALSO

crontab(1), crontab(5), make.conf(5), build(7), firewall(7),
release(7),
tuning(7), diskless(8)

HISTORY

The development manual page was originally written by
Matthew Dillon
<dillon@FreeBSD.org> and first appeared in FreeBSD 5.0, De
cember 2002.
BSD December 21, 2002
Copyright © 2010-2025 Platon Technologies, s.r.o.           Home | Man pages | tLDP | Documents | Utilities | About
Design by styleshout