[mod.unix] Unix Technical Digest V1 #33

Ron Heiby (The Moderator) <unix-request@cbosgd.UUCP> (03/26/85)

Unix Technical Digest       Tue, 26 Mar 85       Volume  1 : Issue  33

Today's Topics:
                            Administrivia
                             make depend
                Multi-step implicit rules for make(1)
             What's wrong w/this makefile?  (.SUFFIXES:)
       What's wrong with this picture (makefile bug?) (2 msgs)
----------------------------------------------------------------------

Date: Tue, 26 Mar 85 19:48:58 GMT
From: Ron Heiby (The Moderator) <unix-request@cbosgd.UUCP>
Subject: Administrivia

The last four articles in this digest are in response to a question on
"make" that was included in Volume 1, Issue 26 of the mod.unix digests.
I have received several notes indicating strong interest/confusion
regarding "make", so have included all four in their entirety, although
some of the material is duplicated.  Each contains valuable information
on how "make" works and should be used.  The first article is from another
conversational thread, but looked interesting.

The only commonly available documentation on "make" that I have found to
be of any use is in the "Unix System V - Release 2.0 Support Tools Guide"
from AT&T, April 1984, 307-108, Issue 2.  I don't know what it costs.  Many
other tools are described in there, as well.

Ron.

------------------------------

Date: 24 Mar 85 21:49:19 GMT
From: throopw@rtp47.UUCP (Wayne Throop)
Subject: make depend

> > ...
> > People don't keep their dependency lists up to date, things
> > ...
> > 	Guy Harris
> 
> I agree entirely with Guy concerning the importance of automated
> dependeny generators.
> ...
> The solution is to use ONLY source files as a basis for
> dependency generation.
>  ...
>     Kim Walden

Kim's solution seems quite good given the way make works.  If you are
willing to change make's model of the world, another solution becomes
available.  In particular, if a make-like tool allowed dependencies to
be specified dynamically, the problem of intermediate files being needed
before make is invoked (to allow dependencies to be discovered) becomes
a non-problem.

There are many ways for make to be modified to allow for dynamic inputs,
but suppose a syntax something like

    foo.o: foo.c (foo.c; find_includes foo.c)
            cc -c foo.c
    foo.c: foo.x
            make_c_from_x foo.x

The parenthesized text specifies a list of inputs to the "command"
at the end of the list.  The output of the command will be a list of
include files, and the effect is as though that list of files had been
supplied instead of the parenthesized text.  What make would do for
this makefile fragment would be to invoke make_c_from_x, then invoke
find_includes (discovering any include file dependencies of foo.c),
and then cc foo.c, producing foo.o.

This is essentially an "incremental make-file generator".  It has problems,
such as what to do about include files that include other files, and so
on, but these problems can be overcome.  Note also that make would then need
a database of already-run dynamic input lists, for efficency (otherwise
it would need to re-run find_includes every time make runs, not just when
foo.c changes).

------------------------------

Date: 20 Mar 85 23:48:50 GMT
From: hoey@nrl-aic.ARPA (Dan Hoey)
Subject: Multi-step implicit rules for make(1)

In <177@osiris.UUCP> eric@osiris.UUCP (Eric Bergan) has a problem with
make's use of implicit rules.  An example of the problem can be seen
with a makefile like

    .SUFFIXES: .D .C .B .A

    CONVERT_A_TO_B=cp
    CONVERT_B_TO_C=cp
    CONVERT_C_TO_D=cp

    .A.B:
	    $(CONVERT_A_TO_B) $< $@
    .B.C:
	    $(CONVERT_B_TO_C) $< $@
    .C.D:
	    $(CONVERT_C_TO_D) $< $@

    all:    foo.D

Executed in a directory with only makefile and foo.A, this make will
complain that it doesn't know how to make foo.D.

As both howard@cyb-eng.UUCP (Howard Johnson) and greg@ncr-tp.UUCP (Greg
Noel) have pointed out, the problem is that for an implicit make rule
".A.B" to be invoked foo.A must either exist or be mentioned as a
target or dependent in some rule.  Thus the problem can be circumvented
by the addition of the dependency
    foo.D: foo.B foo.C
or even
    foo.C: foo.B
in the makefile.  One problem with adding lines like this is that they
must be added for bar.D, baz.D, ad infinitum.  Another problem is that
the methods fool make's error handling.  If we instead add the line
    foo.D: foo.B
make will create only foo.B, with no complaints.  The problem is that
it treats "foo.D" as a target like "all" in this case, not as a file
that must be created.

We now turn to methods for getting make to use implicit rules to create
foo.D.  Both Howard and Greg propose adding a rule like
    .A.D:
	    $(CONVERT_A_TO_B) $< $*.B
	    $(CONVERT_B_TO_C) $*.B $*.C
	    $(CONVERT_C_TO_D) $*.C $@
(their solutions are identical except for Greg's cleanup line
	    rm -f $*.B $*.C
) to the makefile.  In this case, with four suffixes involved, we might
want to also add rules for .A.C: and .B.D:.  I find these methods
unsatisfactory because of the proliferation of the information about
the commands used for converting one object into another.  For
instance, if the procedure for $(CONVERT_B_TO_C) took the arguments in
the opposite order, we would have to change the information in two or
three rules.

I would suggest that the rules to be added should tell make to
use the previously defined implicit rules, for example
    .A.D .B.D:
	    @make $(MFLAGS) $*.C $@
	    rm -f $*.C
    .A.C:
	    @make $(MFLAGS) $*.B $@
	    rm -f $*.B
There are a few things to watch out for here.  For one thing, the
inclusion of $(MFLAGS) does not pass all of make's invocation to the
subsidiary make.  If you expect to invoke this script as, for instance
``make CONVERT_B_TO_C=mv'', you must set up the recursive invocations to
say ``@make CONVERT_B_TO_C=$(CONVERT_B_TO_C) $(MFLAGS) ...''.  It is
clear this could get out of hand.  And if you like to try things out
with ``make -f fakefile'' you had better forget this approach entirely.

Another thing to watch out for is the ordering of ".SUFFIXES:".  The
dependents of .SUFFIXES must be in reverse temporal order for this to
work.  Since lines like ".SUFFIXES: .A" append to the list of suffixes,
this is sufficient if you want to add preprocessors to your source
files.  If you want to add postprocessors to targets already known to
make, be sure to start with a ``.SUFFIXES:'' line with no dependents.

It would of course be nicer if we could get make to know how to
recursively apply its own implicit rules as it does for explicit rules,
but I suppose there are problems with that.

Dan Hoey
Navy Center for Applied Research in Artificial Intelligence

------------------------------

Date: 14 Mar 85 21:58:57 GMT
From: howard@cyb-eng.UUCP (Howard Johnson)
Subject: What's wrong w/this makefile?  (.SUFFIXES:)

The problem with Mr. Bergan's makefile stems from the evaluation of the
.SUFFIXES dependencies.  His goal was to have a preprocessor perform some
transformation on his source code and produce C code (presumably "cat" is
for illustration).  The solution:

	.SUFFIXES:	.qc

	mtest:	mtest.o
		$(CC) -o $@ mtest.o

	.qc.o:
		cat $< > $*.c
		$(CC) $(CFLAGS) -c $*.c

	.qc.c:		# optional rule so "make mtest.c" works
		cat $< > $*.c

The problem with Mr. Bergan's first example is discussed below:

>	.SUFFIXES: .qc
>
>	.qc.c:
>		cat $< >mtest.c
>
>	mtest: mtest.o
>		cc -o mtest mtest.o

First, "make mtest" is invoked.  Unless a .SUFFIXES: dependency with nothing
after the colon is given (to clear default dependencies), the .qc suffix is
appended to a default list producing something like:

	.SUFFIXES: .o .c .e .r .f .y .yr .ye .l .s .qc

"mtest" depends on "mtest.o".  Since there are no explicit dependencies for
mtest.o, the .SUFFIXES list is scanned.  Note that the first suffix
which has an implicit dependency for .o is .c.  Several other implicit
dependency rules are found, but none of them have the inferred prerequisites
either.  (This includes the .qc prerequisite, since there is no .qc.o rule.)
Hence, *make* gives up, complaining that (most likely) the prerequisite
mtest.c file is missing.

Mr. Bergan's quick fix (including the explicit "mtest.o: mtest.c" dependency)
works because it forces make to match the .SUFFIX dependencies for a .qc.c
rule.

After wading through a few 10-page makefiles, one soon has motivation to
learn about details such as this.
-- 
	Howard Johnson		Cyb Systems, Austin, TX
		cyb-eng!howard@ut-sally.ARPA or
..!{gatech,harvard,ihnp4,nbires,seismo,ucb-vax}!ut-sally!cyb-eng!howard

------------------------------

Date: 15 Mar 85 17:07:00 GMT
From: gdsd1@homxb.UUCP (M.LAI)
Subject: What's wrong with this picture (makefile bug?)

Try:

.SUFFIXES: .qc

.qc:
	cat $< > $(?:.qc=.c)
	$(CC) $(CFLAGS) -o $@ $(?:.qc=.c)
	@rm $(?:.qc=.c)

and you won't need to specify any dependencies.  Just:

	$ make mtest
	cat mtest.qc > mtest.c
	cc -O -o mtest mtest.c

Neal Nuckolls
..!houxa!homxb!gdsd1

------------------------------

Date: 19 Mar 85 05:49:47 GMT
From: greg@ncr-tp.UUCP (Greg Noel)
Subject: What's wrong with this picture (makefile bug?)

In article <177@osiris.UUCP> eric@osiris.UUCP (Eric Bergan) writes:
>......................................... Has anyone gotten user defined
>suffixes to work correctly?

Er, I don't know how to break this to you, but make is working exactly
as advertised; it is your makefile that is not correct.  The thing you
need to understand is that make will take no leaps of faith in finding
the files it needs -- in other words, it won't chain rules together.
In particular, the fragment:

>	mtest: mtest.o
>		cc -o mtest mtest.o

says that mtest depends upon mtest.o -- a reasonable thing.  Since mtest.o
does not exist, make now tries to find a way to make it.  It does this by
searching for a rule of the form ".XXX.o" for which mtest.XXX \already/
\exists/.  It can't find it, hence it says "don't know how to make mtest.o".

> However if I do "make mtest.c" and then "make mtest" it works fine.

Yep -- it knows how to convert mtest.qc into mtest.c using the rule you
have given and it knows how to convert mtest.c into mtest.o using the
built-in rule, but it won't chain the rules.  If you think about it, this
is a reasonable restriction: suppose you have the rules .y.c, .y.s, .c.o,
and .s.o and you want to convert xx.y into xx.o -- there are two possible
paths (.y => .c => .o and .y => .s => .o) and it couldn't chose between
them.

>	If I change the makefile to:
>
>	[ same as before ]
>
>	mtest.o: mtest.c
>
>and the only file is "mtest.qc", and I do a "make mtest", it works fine.

Again true -- this time you have given make an explicit dependancy so that
make knows that it must create mtest.c, so it searchs to find a rule
.XXX.c for which a file mtest.XXX already exists; it finds the rule .qc.c
and the file mtest.qc.  It then applies the rule, making mtest.c, and then
tries to make mtest.o again.  Since you didn't give any specific actions
for making mtest.o, it applies the search rules again, looking for a rule
.XXX.o and a file mtest.XXX; this time it finds .c.o and mtest.c.  (Just
because you said you needed it doesn't mean that make will use it -- if you
had a mtest.s in the directory (and the .SUFFIXES were in a slightly
different order), this makefile would make mtest.c as you told it, but
then it would make mtest.o by assembling mtest.s.  It can be confusing
at times......)

To cause make to combine the rules in the way you want, you must explicitly
tell it how.  I.e., you must have a rule that goes from your special suffix
all the way to the desired object:

	.SUFFIXES: .qc

	.qc.o:
		cat $< >$*.c
		$(CC) $(CFLAGS) -c $*.c
		rm -f $*.c

Hope this helps.
-- 
-- Greg Noel, NCR Torrey Pines       Greg@ncr-tp.UUCP or Greg@nosc.ARPA

------------------------------

End of Unix Technical Digest
******************************
-- 
Ronald W. Heiby / ihnp4!{wnuxa!heiby|wnuxb!netnews}
AT&T Information Systems, Inc.
Lisle, IL  (CU-D21)