Subject: Re: [PATCH] yacc: fix VPATH builds with FreeBSD make

From: Stefano Lattarini <[email-masked]>
Date: Sat, 29 Jan 2011 11:31:15 +0100

On Saturday 29 January 2011, Ralf Wildenhues wrote:
> * Stefano Lattarini wrote on Fri, Jan 28, 2011 at 01:51:40PM CET:
> > On Thursday 27 January 2011, Ralf Wildenhues wrote:
> > > Does 'make -n' create files (for any target)?
> > >
> > No, and I've updated the `yaccdry.test' testcase to also check for this
> > (see attached amended patch).
> 
> Thanks.
> 
> > > How do you ensure in your patch that 'make distdir' does not create files?
> > >
> > Well, it does, but I don't see any problem with this.
> 
> Ah, you're right.  I was confused here.
> 
> > > How do you ensure in your patch that 'make clean' does not create files?
> > >
> > In fact, it does (good catch, BTW); see new testcase in the attached patch.
> > Yes, this is clearly a wart, but a minor one, and having it is IMHO a price
> > worth paying in order to have VPATH builds work on FreeBSD.
> 
> Wait.  When you do '../configure && make clean', then your code creates
> the files just before removing them again, no?
>
Actually no, it's worse, because the files are copied by "make clean", but
removed only by "make maintainer-clean".

> That is what I meant.
> It is not a disqualifying problem that it does so, but it is not nice.
>
See above.

> It becomes more of a problem when things like
>   make tags
>   make some-arbitrary-user-target
> 
> start creating files that they shouldn't have anything to do with.
> OTOH,
>   make some-prog-that-depends-on-yacc-output
> 
> should be built with updated yacc outputs.
> 
> > BTW, if you decide to get rid of said wart in a follow-up patch, that can
> > probably be done using the FreeBSD make special variable `.TARGETS' (akin
> > to GNU make's `MAKECMDGOALS').
> 
> I suppose, yes.
> 
> Another problem, which might be more serious:
> 
> Say I checkout a git tree of my project, do a VPATH build from it on
> FreeBSD.  The next day someone has updated foo.y in git, I pull the new
> version, type 'make' again inside the old build tree.  This fails to use
> the code from the new foo.y code version (because at the time the .BEGIN
> rule was invoked, the old $(srcdir)/foo.c was still in place).
>
No, it should work anyway.  I see three scenarious:

 1. You have a pre-existing `foo.c' in the builddir.  After you update
    the `foo.y' in the srcdir, you run "make".  The .BEGIN target will
    do nothing, because there's already a `foo.c' in the builddir; then,
    since this `foo.c' is older than the `foo.y' in the srcdir, make
    will rebuild it.  From there, everything should go as expected.

 2. You have a pre-existing `foo.c' in the srcdir, but not in the
    builddir.  You update the `foo.y' in the srcdir, which will make
    it newer than `foo.c'.  Then you run "make".  The .BEGIN target
    will copy the `foo.c' from the srcdir in the builddir, using the
    cp -p command; this means that the timestamp of `foo.c' will be
    preserved, so that the `foo.c' in the builddir will result older
    than the `foo.y' in the srcdir -- and will thus be rebuilt by
    make.  At this point, `foo.c' is really up-to-date with the new
    `foo.y', and from there, everything should go as expected.

 3. There's no pre-existing `foo.c' in the srcdir nor in the builddir.
    The .BEGIN target will do nothing, because there's not `foo.c' in
    the srcdir to copy.  Make will then create (in the builddir) the
    `foo.c' derived from `foo.y'.  From there, everything should go as
    expected.

> I use such setups regularly.  I know they break when the source tree
> changes are large, but still, with no source tree graph changes it is a
> subtle failure that developers will rightly blame Automake for.  It can
> be fixed by comparing time stamps, at the cost of now getting into the
> time stamp business that I mentioned earlier.
>
There should no need to; and the fact that the behaviour you want really
works should be already verified by the test `yaccvpath.test' (which you
are free to improve if you like, I obviously won't object ;-)

> Then, there is the issue of which make implementations support the
> .TARGETS feature.
>
You mean the ".BEGIN" feature here, right?

> What if GNU make 3.84 starts supporting it?
>
Then we start checking in the `.BEGIN' recipe that the currently-running
make is really a BSD make (e.g. by checking that ${.MAKE.PID} is
non-empty, or something like that).  If it's not a BSD make, we exit
early from the recipe.

But then, that wouldn't be really necessary, since the setup done by
the `.BEGIN' recipe shouldn't break builds for non-BSD makes: it's just
redundant for them.  So, even if GNU make 3.84 starts supporting the
`.BEGIN' target, Makefiles generated with automake 1.12 should still
be able to build packages using Yacc correctly.

> Our makefiles then would suddenly cause regressions for GNU make users.
>
How so exactly?

> I guess my point is, I fear that your approach is fundamentally not
> robust.  I acknowledge that BUILT_SOURCES is not robust either
> ($(BUILT_SOURCES) being updated routinely as part of 'all', 'check',
> 'install', but no other special targets).  But at least with dependency
> tracking enabled, BUILT_SOURCES is typically needed only the first time
> 'make' is used in some build tree.
>
Which BTW is also the way the `.BEGIN' recipe we're using should
behave, ideally ...

Hmm... Maybe having a similar (internal) variable `am__LINKED_SOURCES'
holding a list of files to be copied from srcdir to builddir *only for
targets 'all', 'check' and 'install'* might be a better stategy?
Should I try to pursue that?

> Cheers,
> Ralf

Regards,
  Stefano