Editing makefiles is tedious and errorprone. Genmake
is a collection of csh and awk scripts that can automate
most of the process. Unfortunately, editing csh and awk scripts
is also tedious and errorprone. But if you use genmake, the dirty
work is already done for you.
What is Genmake?
Genmake is simply a program that examines your source code directory tree
and creates or updates a corresponding "build directory" somewhere
else (you tell it where). The build directory contains a makefile
that can build all of the code in the source directory using almost any
version of the make utility.
When genmake is finished, you compile and build your programs directly
in the build directory, by cd'ing into the build directory and typing
make (target), just as if you had created the makefile
yourself. As make runs, the sources are read from the source directory,
but all objects and executables end up in the build directory.
If you define the right shell variables before you run genmake
(see instructions below), the resulting
makefile will have all of the right rules to build your programs on
whatever type of system you ran genmake on. Note: if you add, move, or delete any
files in your source directory, then you must run genmake again to
update the rules in the build directory. Note: make sure the noclobber
option in your shell is disabled, or you may get a "file already exists" message.
of genmake includes a template for building multi-threaded
C++ programs on Duke CS Sun and Alpha workstations for the CPS 210 class.
If you run genmake on an alpha then you must build on an alpha. If you
run genmake on a sun you must build on a sun. Genmake can be used to create
two separate build directories (one for alphas and one for suns)
building from the same source code.
Why should I bother with genmake?
- Genmake creates the makefile so you
don't have to, and it ensures that the makefile is "in sync" with your
source code at the time you run genmake.
- Genmake includes the right rules to build your programs on our
machines here at Duke, so you don't have to figure out what
libraries to link in, which compilers to use, which flags to pass, etc.,
and we don't have to help you if you get it wrong.
- Your object files are cleanly separated from your sources, so you
can have multiple builds from the same set of sources (e.g., from different
types of machines), and you can clean things up just by removing the
- All object files are built with full source pathnames, so a debugger
such as gdb can always find the source file for a particular line
of code, no matter where you run the executable.
How do I set up genmake so I can use it?
To "install" genmake for your use, follow these easy steps:
- Add the genmake directory to your PATH shell variable. You should
do this in a definition file automatically read into your shell when you
log in. At Duke, put it in your .environset file. For CPS 210, you should
use the genmake in /usr/project/courses/cps210/genmake.
- Define a shell variable BUILD_TOOLS_DIR whose value is
the pathname of the genmake directory (this is where genmake
expects to find its auxiliary scripts). Again, put it in .environset.
- Define a shell variable BUILD_TOOLS_WHICHSYS whose value is either
"sun" or "alpha". Again, put it in .environset, and set it up so that
the variable gets the right value automatically, depending on what system
you're logged in on. For an example of the cleanest way to do this, see
Geoff Cohen's .environset file; it has a small fix to set the
CPU shell variable at the top, then it sources a system-specific version
of a file called .buildset from bin/alpha or bin/sun4,
depending on which system he logs in on. The .buildset file defines
the right shell variables for genmake.
How do I build my programs with genmake?
To use genmake on a package of source code, follow these
- Put all your code into a clean directory tree with no
makefiles. If your source directory has subdirectories, then
you should specify your include paths relative to the root of
your source directory. For example, if you have subdirectories
misc and sets, then source code in sets can/should
include headers in misc as (say) misc/Types.h rather
than ../misc/Types.h or Types.h.
- Run genmake source build where source
is the name of your source directory, and build is the
name of the directory in which you will type "make" and build your
objects and programs from the source. If build does not
exist then it is created. It is safe to re-generate into an
existing build (object) directory. Only the make files and templates are
updated; existing object files are not disturbed.
- If you have any source files that need to be compiled with a C
compiler rather than a C++ compiler, list them in a file called
cfiles.lst ("cfiles dot list") at the root of your source
directory. List them using "dot-relative" names from the root of
the source directory, e.g., "./sets/mycfile.c".
- If you move to a different type of host system (e.g., from a sun to an
alpha) or if you change the shape of the build tree (e.g., add or delete files,
change prog.lst, add new headers) then you should run genmake again before
building. It is safe to run genmake over an existing build directory;
all of your previously build objects will be preserved. However, if you have
noclobber enabled in your shell then genmake cannot modify an existing
build directory; you must create a new build directory (e.g., rm -rf the old
one before running genmake again).
Does genmake really work?
There are a number of restrictions with this version of genmake.
- Genmake ignores all source files that do not end in .c,
.h, or .s extensions. New rules can be added, so let me know if you like to use a
different extension. Some people like to use .C for C++ files and .c for
C files, or whatever.
- Genmake will FAIL if your source directory tree contains
multiple files with the same name. Keep your source directories clean;
put any backup copies elsewhere.
- This version is
not very graceful when source and object are the same directory.
So don't do that. Building in a separate directory has lots of advantages,
particularly for group projects or software that runs on multiple systems
or architectures. That is one reason why genmake was created.
- One of the last things genmake does is run "make depend", which
generates a list of dependency rules, so that (for example) the right
objects will be rebuilt if you modify a header file. You'll see this
because make depend will print lots of your source file names at
you. This is normal. Make depend may also print some warnings if some
header files could not be found. This won't prevent correct code from
building correctly. Note: the program "makedepend" is not always
where you expect it; it is in /usr/bin/X11 on most platforms. This must
be in your $PATH shell variable or you will get a "makedepend: not found"
error message when you run genmake.
Make depend is buggy on most platforms
(MIT code) and may bail out before finishing. If this happens, your
code will still build, but the makefiles may fail to rebuild all the
objects that need to be rebuilt when you change something. If your
bug fixes don't appear to "take", or if new inexplicable bugs appear
when you make a minor change in a header file, protect yourself by
typing make scratch and then rebuilding everything before you
spend hours debugging. (This is not a genmake problem.)
- Genmake is not very robust. It works for me, but don't expect it to
work if you try anything weird. If it fails, it may fail silently,
leaving you with an incomplete makefile. Genmake will tell you if it
completed successfully. If you don't see an output message like this,
then genmake probably didn't do everything it should have done. This
should not happen if you follow the directions above, but let me know
if you have any problems. Problems most often result from garbage in
prog.lst or cfiles.lst., or building on a nonstandard
machine...though genmake is easily customized to any Unix system by
modifying the templates.
- The output of genmake is simply a makefile and some other related
files. Feel free to examine the output of genmake or even to modify it
for a quick fix. Of course, if you run genmake again then your changes will