Managing third-party source code with CVS

Chris Houghten



This paper continues on where Luke Mewburn leaves off in his paper describing techniques for using revision control and documentation to install and maintain third-party source code.


Please see Luke Mewburns paper and then return here to see my clarifications His paper can be found at

I really did not like the outcome of Lukes procedure. What I really wanted was a way to have my code changes isolated. In my opinion, none of the third party code itself is of amy importance to me personally and I just need it checked in my CVS repository so I can build it. In my case, the versions of the third party code were so different that simple merging was not an option and the errors I was getting were so generic that I needed to be able to isolate my code and possible manually merger them in one at a time.

Anyway, my procedure is as follows: 1: import the new package as described by Luke 2: Checkout the module as described by Luke 3: Make your changes as described by Luke 4: Run update as described by Luke 5: Commit your changes as described by Luke 6: TAG ALL THE FILES YOU JUST COMMITTED USING A AG SPECIFICALLY FOR ONLY YOUR CODE 7: Import the new version of the third party source as described by Luke 8: Checkout the module MERGING THE NEW VERSION WITH ONLY YOUR SOURCE 9: Update as described by Luke 10: commit your changes as described by Luke 11: TAG ALL THE FILES YOU JUST COMMITTED USING A NEW TAG SPECIFICALLY FOR ONLY YOUR CODE Theses tags you make for your source code allow you to checkout just your code so you can see what you have changed and manually merge/copy/mangle it to get it to work with the newer version of the third party source It also allows you to be able to completely disregard the older third party source because that source essentially no longer exists and the merging from the old third party version to the new one was already done by that third party This is especially true and useful when skipping versions or when the third party completely changed their code through refactoring or eliminating of some code and merging is more or less impossible.

Importing a new package

To import a new package, we require a fresh copy of the source. Suggested locations to look for software are described below in Finding third-party source.

In this example we will use the Internet Software Consortium's DHCP server - dhcp 2.0b1 pl18.

Updating an existing package

It is rare for third-party software to remain unchanged forever; updates are available (even on a regular basis).

An important part of managing third-party software is upgrading to a newer version in a sane way.

The process to import an updated version of a package is similar to importing the original package. However, because changes in the newer version may conflict with any local changes that you may have made to the product, there are a couple of steps that are different.

In this example, we'll be upgrading dhcp 2.0b1 from pl18 to pl27.

Advanced CVS operations

CVS has other operations which are useful to know. Whilst these may be more relevant to a software developer, they are still useful for our purposes:

Tips and Tricks

CVS is a powerful tool and it has useful functionality that is often only hinted at in the documentation. This sections covers some of that functionality, and other tips and tricks that I felt might be relevant.

cvs checkout -j old-vendor-release -j new-vendor-release module

In my opinion, this is one of the most useful underdocumented operations in CVS, especially for the purpose of maintaining third-party packages (or anything that uses vendor branches).

As shown in the example in Updating an existing package, this operation checks out a copy of module and merges any changes made by the vendor between release tags old-vendor-release and new-vendor-release. This includes files that were added or removed between releases.

Tagging the installed release

It may be useful to tag a package at a known working state after successful installation or prior to the import of a new version. This can simplify determining the local changes made to the previous vendor release.

The sequence of operations would be something like:

Minimising conflicts

It is possible to modify code to minimise conflicts when the vendor changes the same sections of the code. Rather than change a line provide an override line which has the same effect.

Binary files

Certain packages are distributed with binary files that must be stored unmodified in the repository and be checked out unmodified upon a check-out.

The simplest way to support a package with some binary files is:

Symbolic links

CVS ignores symbolic links upon import (the files have a status of "L").

A workaround is to add a local script to module which is run manually after checkout to regenerate the symlinks. I call this fixlinks, and generate it with:

	% find . -type l -print | perl -e 'while (<>) { chomp ; \
	    print "ln -s ", readlink($_), " $_\n"; } ' > fixlinks

An example fixlinks (from our net/netatalk package) is:

	ln -s ../sys/netatalk ./include/netatalk
	ln -s ../codepage.h ./etc/afpd/nls/codepage.h
	ln -s kpatch-4.2 ./sys/ultrix/kpatch-4.4
	ln -s kpatch-4.2 ./sys/ultrix/kpatch-4.3
	ln -s ../../ultrix/sys/cdefs.h ./sys/solaris/sys/cdefs.h

Upon checkout, regenerate the links with:

	% sh ./fixlinks

Automatically generating modules file

The CVSROOT/modules file provides a mapping from a module alias to a directory or directories. I find it useful to have shortcuts to the packages in the repository. For example, this allows me to run cvs checkout dhcp instead of cvs checkout net/dhcp.

I wrote a script a few years ago called genmodules [7] which which parses CVSROOT/commitlog and updates CVSROOT/modules as necessary.

Working with multiple repositories

If you are working with multiple repositories (e.g., a local repository and that of an open source software project), it may help to have shell aliases which do the right thing.

For example, in my .cshrc I have:

	alias   ncvs    'env cvs'
	alias	cscvs	'env CVSROOT=wombat:/src/cvsroot cvs'

Setting defaults for CVS commands

If you are always invoking a CVS command with the same set of options, you can simplify your typing by adding a relevant entry in $HOME/.cvsrc. For example, I have a line of the form:

	update -dP

which means that cvs update ... is run as cvs update -dP ... ("-d"; build directories, "-P"; prune empty directories).

Organising the repository

It is highly recommended to have a sensible organisation for the third-party packages in the repository. For example, we have the following directories; it should be trivial to infer the contents of the directories:

	% ls $CVSROOT
	CVSROOT     devel      lang       rmit       www
	ai          docs       mail       security   x11
	archivers   file       net        text
	audio       graphics   news       utils

Finding third-party source

An element of managing third-party source is finding the source in the first place :-) A few good places to look include:


I believe that CVS is well suited to the task of managing third-party software. I have been using it this role for over five years for three different employers. For over three years I have also been using CVS as one of the many distributed developers of the NetBSD project [8].

Before I started my current position at RMIT Computer Science nearly two years ago, /usr/local/src was a two gigabyte directory with a haphazard structure (I hesistate to call it "organisation"). In many cases there multiple copies of the same product, without any obvious indication of which was the currently installed version (in the case of the Columbia Appletalk Package there were six different versions of the source code). As we rebuilt systems (including rebuilding /usr/local from scratch on new machines), we kept all new products in the CVS repository.

Hand in hand with CVS is the maintenance of relevant documentation. Without documentation a CVS tree is almost as bad as the proverbial unorganised /usr/local/src. NetBSD provided the inspiration for the 3RDPARTY file, although I have expanded upon it since then.


Thanks to Matt Green for teaching me the checkout -j old -j new module trick (amongst others); in my opinion it is one of the most useful commands to know when maintaining third party source.

Giles Lean's assistance by reviewing the paper and providing a wealth of feedback was much appreciated.


[1] Cyclic CVS site,
[2] CVS Overview,
[3] Introduction to CVS,
[4] The CVS info documentation.
This should be installed as part of the CVS installation.
[5] CVS Reference Manual,
[6] SSH secure shell,
[7] genmodules,
[8] The NetBSD Project (Australian mirror),