[net.unix] make and archives - dependency problem

grt@hocda.UUCP (G.TOMASEVICH) (04/16/84)

This is in part a reply to mail.  Yes, is is more efficient to use archives
rather than directories of files, but somebody should fix 'make'.
On systems I have used (USG UNIX pre PWB/UNIX through USG 4.2, PDP11 & VAX)
apparently 'make' only looks at the age of an archive.  It ought to open
the archive and read the ages of the constituent files, according to which
ones are named in the dependency.  Because it does not, I fake out 'make'
in the following way:

1. Indicate that an object archive depends on the .c files.  Example:

	ar.a:: part1.c
		make obj FILE=part1
	ar.a:: part2.c
		make obj FILE=part2

2. The execution code this invokes is

	obj:	$(FILE).o

	$(FILE).o:	$(FILE).c
		$(CC) $(FILE).c

3. The final dependency for the archive is like

	ar.a:: artmp

	artmp:;	$(ARCH)

   At the top of the makefile, ARCH is defined to call a shell script.

4. The script checks to see whether any .o files have been made; if so
   the archive is updated and then the .o files are deleted.  This is a
   real kludge now; somewhere along the line from the Mashey to the Bourne
   shell and the latter's evolution, the shell script broke several times.

5. Note that when the archive does not exist, as for a port to a new UNIX
   release, it is necessary to get all .o files made before the archive
   be created the first time.  Once made, the archive will be newer than the
   .c files.  If any compilation errors occur, get through them before
   lettting the archive get made.  This is very slow on restarting for my
   graphics program after about 30 of the .o files exist, since 'make'
   goes through all of the 'make obj' steps every time it is restarted.

6. Sample ARCH for my graphics program on VAX and PDP USG UNIX 4.2:

	ARCH = ../fpt.a.sh edcx?.o

  Contents of ../fpt.a.sh:

	if [ "$*" != 'edcx?.o' ]
	then
		echo fpt.a:
		ar rv fpt.a $*
		echo rm -f $*
		rm -f $*
	fi
	exit 0

   In an earlier Bourne shell 'edcx?.o' was passable without metacharacter
   expansion, but no more.

	George Tomasevich, AT&T Bell Laboratories

crl@pur-phy.UUCP (Charles LaBrec) (04/17/84)

"Make" has understood archives since version 7.  If a dependency of
the form "arch(foo.o)" is given, make will look up foo.o in arch.a
and use the modified time inside the archive.  Also available is
a dependency of the form "arch((_foo))" that looks up the entry point
"_foo" in arch.a and uses the modified time of the .o file that contains
it.  (I don't have any documents handy, but with the amount I looked at
Make recently, I think the above is the correct syntax.)

System V Make handles archives even better.

Charles LaBrec
UUCP:		pur-ee!Physics:crl, purdue!Physics:crl
INTERNET:	crl @ pur-phy.UUCP

thomas@utah-gr.UUCP (Spencer W. Thomas) (04/20/84)

After fixing make to check dates on the elements of archives properly,
we came up with the following "solution" to making a large library for
which we didn't want to keep all the .o files around.  Warning: this is
horribly convoluted and awful, but it is all generated automatically by
our make-depend script, so we don't worry too hard about that.  You need
(as it turns out) two auxilliary files, which we call 'didwork' and
'donework'.  Below is a makefile fragment, with some explanation of what
is going on.  We also put in a "FASTLIBS" switch to prevent the n**2
behaviour that make exhibits when checking the dates on all elements of
a library (by default, make rereads the library for each element).
FASTLIBS caches the dates incore.  It works fine with the paradigm
below, and is much faster on a large library.

=Spencer

default: updatelib

#
# Files which go into the library.  These are the targets of the make.  Rules
# for generating them are below.
#
OFILES= libI.a(D_trim_tri.o) libI.a(S_trim_tri.o)

#
# newlib - Make the intersection library from scratch
#
newlib: cleanlib updatelib

#
# updatelib - Update the intersection library
#
# explanation: 
# 1. reload the library with any .o files hanging around, so we don't need
#    to recompile them.  Assumption is that they came from a previous make
#    which bombed out because one compilation failed.
# 2. compile all the .o files.  We are fooling make here, by telling it that
#    we are making libI.a(ofile) when we are really making just the ofile.
#    Thus, we touch didwork, to force the updatelib stuff to be run even
#    though the dates on the library elements have not changed (yes, make
#    checks again after the rule is executed!)
# 3. The csh ... line causes the ar to not be done if there are no .o files,
#    avoiding the cost of an unnecessary ranlib.
# 4. Touch the updatelib file to make it up to date, and
# 5. Reset the dates on didwork and donework (really shouldn't be necessary,
#    maybe isn't, just left in as a superstition.)
#
updatelib: libI.a ${OFILES} didwork
	-csh -cf "ar r libI.a *.o && rm *.o && ranlib libI.a"
	touch updatelib
	setdate 'jan 2 1970' didwork donework

#
# Just load .o files hanging around.
#
# This depends on donework instead of didwork.  Both donework and didwork
# always have the same date, but for some reason, once make checks the date
# for a dependency it refuses to believe that you might have changed the date
# behind its back.
libI.a: donework
	-csh -cf "ar r libI.a *.o"
	-rm *.o
	ranlib libI.a
	setdate 'jan 2 1970' didwork donework


#
# cleanlib - delete the library so we can start afresh - make a new empty one
#
cleanlib:
	rm libI.a
	ar rc libI.a


# 
# Make the .o files (automatically generated by make-depend).
# Touch both didwork and donework.  The files are supposed to indicate:
# didwork: some work was done in this invocation of make (some files were
#	   compiled).
# donework: some work was done in the last invocation of make, but the
#	    library has not yet been updated.
#
libI.a(D_trim_tri.o): D_trim_tri.c
	${CC} ${CFLAGS} -c D_trim_tri.c
	touch didwork donework

libI.a(S_trim_tri.o): S_trim_tri.c
	${CC} ${CFLAGS} -c S_trim_tri.c
	touch didwork donework