Go to the previous, next section.

Converting an existing large program

This is the sequence of steps I did to convert James Theiler's xyplot to use autoconf.

There are a few subdirectories involved: `xydoc', `xyplot', `xysee'.

Dumb work

First you have to do the mechanical stuff.

In the subdirectories

cd xydoc
cp Makefile Makefile.orig               # save the originals
mv Makefile Makefile.in
autoheader
cd ..

Then do the same in the other subdirectories (xyplot and xysee).

At the top level

At the end, I did the top level directory:

cd xydoc
cp Makefile Makefile.orig               # save the originals
mv Makefile Makefile.in
autoscan
mv configure.scan configure.in
autoheader
autoconf
cd ..

Note that I only did `autoheader' in the subdirectories, but I did the full `autoconf' in the top level directory.

Touching up configure.in

Now some things have to be changed in `configure.in':

Then re-run autoconf in the top level directory.

Try it out

At this point you should be able to try it out by typing something like

./configure --prefix=`pwd`/work
make
and if all goes well, you should get almost exactly the same results as before you started this exercise.

Moving toward the GNU coding standards

I then went in to make the Makefiles look a bit more like standard GNU makefiles, with all the targets and variables.

Makefile variables

I changed all the `Makefile.in' files to have the following boiler-plate stuff at the top:

SHELL = /bin/sh
VPATH = @srcdir@

subdirs = @subdirs@
top_srcdir = @top_srcdir@
srcdir = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(exec_prefix)/bin
infodir = $(prefix)/info
libdir = $(prefix)/lib/gnudl
mandir = $(prefix)/man/man1

CC = @CC@
CPPFLAGS = @CPPFLAGS@
CFLAGS = $(CPPFLAGS) @CFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
INSTALL = @INSTALL@

And this stuff at the bottom, so that "make" will automatically reconfigure if the `.in' files change.

# automatic re-running of configure if the ocnfigure.in file has changed
${srcdir}/configure: configure.in aclocal.m4
	cd ${srcdir} && autoconf

# autoheader might not change config.h.in, so touch a stamp file
${srcdir}/config.h.in: stamp-h.in
${srcdir}/stamp-h.in: configure.in aclocal.m4
		cd ${srcdir} && autoheader
		echo timestamp > ${srcdir}/stamp-h.in

config.h: stamp-h
stamp-h: config.h.in config.status
	./config.status
Makefile: Makefile.in config.status
	./config.status
config.status: configure
	./config.status --recheck

Having added these GNU-friendly variables to the `Makefile.in', I removed the original `Makefile.in' material that did similar things, and replaced it with these variables. This is almost always straightforward.

The effect of adding the rules for `config.h', `configure' and so forth is that the programmer never has to remember if she or he has run autoconf or configure recently: the make will figure it out and run what has to be run.

Adding various Makefile targets

It would help if you were to add some of the standard GNU targets to your `Makefile.in', targets such as clean, distclean, install, uninstall.

Here are examples of how that was done for xyplot. Note that xyplot has several `Makefile.in' files. I will show these rules from the top level `$(srcdir)/Makefile.in' (which does very little work: it just invokes the rules from the subdirectories and knows how to make snapshots) and the `$(srcdir)/xyplot/Makefile.in' which is the main workhorse. Keep in mind that xyplot is free software, and you can find it by anonymous ftp from ftp://nis-ftp.lanl.gov/pub/users/jt/Software

Here are some targets from the top level `$(srcdir)/Makefile.in':

all:
	@for dir in ${subdirs}; do \
	  (cd $$dir && $(MAKE) all) \
	  || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
	done && test -z "$$fail"

install:
	@for dir in ${subdirs}; do \
	  (cd $$dir && $(MAKE) install) \
	  || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
	done && test -z "$$fail"
clean:
	/bin/rm -f *~
	@for dir in ${subdirs}; do \
	  (cd $$dir && $(MAKE) clean) \
	  || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
	done && test -z "$$fail"

distclean: clean
	/bin/rm -f Makefile config.h config.status config.cache config.log
	@for dir in ${subdirs}; do \
	  (cd $$dir && $(MAKE) distclean) \
	  || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
	done && test -z "$$fail"

# a rule to make snapshots
snapshot: $(SOURCES) $(DOCS) $(OTHERFILES)
	@echo
	@echo "->Note: The version for now is hacked into Makefile.in as"
	@echo "->" $(VERS)
	@echo
	@echo "->copying all release files to the directory " xyplot-$(VERS)
	@echo
	tar cf - $(SOURCES) $(DOCS) $(OTHERFILES) | gzip > xyplot-$(VERS).tar.gz
	-mkdir xyplot-$(VERS)
	gzcat xyplot-$(VERS).tar.gz | (cd xyplot-$(VERS); tar xf -)
	/bin/rm -f xyplot-$(VERS).tar.gz
	@echo
	@echo "->making the compressed tar file " xyplot-$(VERS).tar.gz
	@echo
	tar cf - xyplot-$(VERS) | gzip > xyplot-$(VERS).tar.gz
	@echo
#	@echo "->placing the snapshot for anonymous ftp in " $(FTPDIR)
#	@echo
#	rcp xyplot-$(VERS).tar.gz $(FTPDIR)
	echo "->removnig the temporary directory " xyplot-$(VERS)
	/bin/rm -rf xyplot-$(VERS)             # remove the old directory

And here are some targets from `$(srcdir)/xyplot/Makefile.in':

install: all
	$(top_srcdir)/mkinstalldirs $(bindir)
	$(top_srcdir)/mkinstalldirs $(libdir)
	$(INSTALL) xyplot $(bindir)
	$(INSTALL) xyps $(bindir)
	$(INSTALL) xyug $(bindir)
	$(INSTALL) xypost $(libdir)

uninstall:
	-/bin/rm -f $(bindir)/xyplot 
	-/bin/rm -f $(bindir)/xyps 
	-/bin/rm -f $(bindir)/xyug 
	-/bin/rm -f $(libdir)/xypost 

# removes whatever can be built with make except xypost
clean:
	/bin/rm -f *.o *~ xyplot xyps squeeze xyug

distclean:
	/bin/rm -f Makefile config.h config.status config.cache config.log

Adding some utility programs to your distribution

You might have noticed that the install: rules used a couple of programs `mkinstalldirs' and $(INSTALL). You should include a copy of `mkinstalldirs' in the top level directory of your distribution. The $(INSTALL) variable gets set by `configure' to be a Berkeley--style install program. If the user does not have a BSD--compatible install program, it is important for you provide the `install-sh' shell script in the top level directory.

So you should grab `mkinstalldirs' and `install-sh' from some other GNU program (such as autoconf, for example) and put them in your distribution.

Cutting a release

Another nice thing that GNU programs almost always do is to create a `program-versionnumber' directory when you unbundle them. The best way to do this is to have a script or a `Makefile.in' target which makes a directory called program-version and copies all the files that need to be distributed into that directory, and then makes a gzipped tar archive of that directory.

You can look at the snapshot: target shown above for xyplot. It first uses a `tar' pipeline to copy the essential files into an appropriately named directory (in this case `xyplot-2.6.0'). Then it uses `tar' and `gzip' to make the file `xyplot-2.6.0.tar.gz', which is ready to be sent out to the world.

It goes without saying that you should try the installation procedure with this `.tar.gz' file on as many versions of UNIX as possible before you publicize the release.

Go to the previous, next section.