[OpenAFS-devel] Re: debian-linux-i386-builder issues

Michael Meffie mmeffie@sinenomine.net
Sun, 8 Sep 2013 22:32:03 -0400


On Thu, 5 Sep 2013 11:17:27 -0400
Benjamin Kaduk <kaduk@MIT.EDU> wrote:

> On Thu, 5 Sep 2013, Andrew Deason wrote:
> 
> > On Thu, 5 Sep 2013 11:07:23 -0400
> > Michael Meffie <mmeffie@sinenomine.net> wrote:
> >
> >> I've seen the same thing happen on debian by just doing a 'make clean'
> >> in, for example, src/bozo.  I recall changing the makefile as Ben says
> >> to replace the $? with the actual filename, but wasn't sure if that
> >> was the right way to fix this.
> >
> > Yes, we should probably do something like what Ben says as a general
> > buildsystem bugfix (I assume he's correct on the details but I haven't
> > really looked). But for buildbot I think it's more urgent to get a
> 
> My mail was from memory, so ... I am not as confident as that.


Aside from the buildbot, I wanted to take a closer look at the build system,
since it is not obvious to me why gnu make is unhappy. I spent some time in
front of make --debug, and this is what I've found.

I started by looking at src/bozo, since that is where I last ran into this.
The error is simple to reproduce.

   $ ./src/bozo
   $ make clean all
   ...
   /usr/bin/install -c -m 644  /.../openafs/include/afs/bnode.h
   /usr/bin/install: missing destination file operand after `/.../openafs/include/afs/bnode.h'
   ...
   make: *** [/.../openafs/include/afs/bnode.h] Error 1


The 'all' rule triggers the 'bos_util' rule. The 'bos_util' triggers the rule to
install the bnode.h into include/afs/bnode.h, which is the rule that fails.

The rules of interest are:

a) install bnode.h

    ${TOP_INCDIR}/afs/bnode.h: bnode.h
        ${INSTALL_DATA} $? $@

b) make bnode.h

     bnode.h: boserr.c

c) make boserr.c

    boserr.c: bnode.p.h boserr.et
        ...
        ${COMPILE_ET} -p ${srcdir} boserr -h bnode


The sequence of events is:

1. The clean target removes bnode.h and boserr.c

2. Rule 'a' triggers rule 'b', since bnode.h does not exist.

3. Rule 'b' declares that bnode.h depends on boserr.c. Rule 'c' is triggered
   since boserr.c does not exist. (Note rule 'b' does not have a command.)

4. Rule 'c' runs compile_et which creates both bnode.h and boserr.c.

5. Since rule 'b' does not have a command, the 'target' is not marked
   as updated by gnu make.

6. Make runs the commands for rule 'a'. At this point gnu-make has not run a
   command for a target of bnode.h, so considers bnode.h to not exist, even though
   it was created by compile_et.  The automatic variable $? is evaluated for items
   that are newer than ./include/afs/bnode.h. Since gnu make does not know
   bnode.h exists at this point, it is not included in the $? value.

The key point here is rule 'b' does not have a command, and there does not
exist a rule for 'bnode.h' that has a command. Looking at the posix
documentation for make, my understanding is, recipes which have a target and
prerequisites, but no commands, are used to add to the prereq list of the
target. There should be one (and only one) target rule that contains commands
for that target. So, I think we are treading into a implementation dependent
area of make here.

The work-around fix is simple. Just give rule 'b' a command, any command, and
then gnu-make has a chance to know bnode.h was updated.  Just adding a ';'
declares an empty command.

     bnode.h: boserr.c ;



However...  this does look odd.  The rule really does not make the bode.h file,
and in fact, bnode.h actually depends on bnode.p.h and boserr.et.  This new,
empty rule, was made to fix parallel makes, if I recall. Since compile_et makes
two files at the same time, two parallel instances would clobber each other.

It seems to me, a more proper fix for all this would be to have a target for
bnode.h and a target for boserr.c which are independent (and the same for all
the other placed compile_et is run).  I was wondering how krb5 copes with
compile_et, and that is basically what the krb5 build system does.  The
downside is compile_et is run twice, but the benefit is a clean build system
that is safe for parallel makes.

In the krb5 build system, two implicit rules are defined. One makes .h files
from .et files, the other makes .c files from .et files.  Each rule makes some
temporary files so they can be run at the some time for a given .et file.

Unfortunately, the openafs rules would be a bit more complicated, since some
of the error tables have 'prolog' p.h files which have a different name than the
error table file. I started looking at how this might work by defining some
general implicit rules for running compile_et. I'll push what I've done so
for to gerrit for comments.

Thanks,
Mike


-- 
Michael Meffie <mmeffie@sinenomine.net>

-- 
Michael Meffie <mmeffie@sinenomine.net>