Subject: bug#13349: Re-execute with the "correct" make implementation

From: Stefano Lattarini <[email-masked]>
Date: Fri, 04 Jan 2013 00:49:43 +0100

On 01/03/2013 11:40 PM, Eric Blake wrote:
> [dropping autoconf]
> 
> On 01/03/2013 03:05 PM, Stefano Lattarini wrote:
>> For usual targets, that is easy.  I don't even think that must be done
>> at Automake-NG level; one can simply use 'GNUmakefile.am' as Automake-NG
>> input file (instead of the usual 'Makefile.am'), add 'GNUmakefile' to
>> an AC_CONFIG_FILES invocation, and then hand-write a simple Makefile
>> acting as a thin wrapper:
>>
>>   TARGETS = all check clean distclean dist distcheck install uninstall
>>   .PHONY: $(TARGETS)
>>   $(TARGETS): ; @gmake $(AM_MAKEFLAGS) $@
> 
> Is that sufficient, or will it bite users that get by with 'make check'
> but then fails when they do 'make file', where 'file:' was a specific
> rule in GNUMakefile?
>
It's only meant as a convenience for the most common cases.

Actually, now that I think about it, the best (because most correct)
convenience would be to have a makefile that simply aborts with a *clear*
*explicit* message if invoked with non-GNU make.  Something like this:

    # Default is to bail out.
    __die__:
        @echo This package requires GNU make >&2; exit 1;

    # Do so also for all the common targets.
    all check install distcheck ... : __die__

    # For Solaris make, we can die for every conceivable target.
    %: __die__

    # Ditto for BSD make and other implementations following POSIX.
    .DEFAULT:
        @echo This package requires GNU make >&2; exit 1;

I've tested the above with FreeBSD make, NetBSD make, Solaris CCS and
XPG4 make, Sun distributed make, Heirloom make, IRIX 6.5 make; it worked
in all cases.

> It's too bad we can't rely on GNU make extensions
> like $(MAKECMDGOALS) as a way to override every single target at once.
> BSD make has $(.TARGETS) as something that looks like it would do the
> same, and we might even get lucky to come up with constructs that work
> nicely in some versions of make without choking any other versions of make.
>
That sounds overkill to me, honestly.  The "abort clearly if run with
non-GNU make" workaround above seems good enough; especially considering
the serious issue brought up by Nick w.r.t. "make -j" usage.

After all, the Git build system requires GNU make, while using a 'Makefile'
rather than a 'GNUmakefile' (yikes), and yet, nobody has complained about
that until today, AFAICS.  So I think we are worrying too much IMVHO.

>> The super-nice developer can even turn this Makefile into a Makefile.in,
>> use '@GNU_MAKE@' rather than simply 'gmake', and (from configure) look
>> for a GNU make implementation in the system and AC_SUBST '@GNU_MAKE@' to
>> its absolute path.
> 
> How much of this niceness should be done by Automake-NG itself, rather
> than making developers duplicate work?
> 
I think that having an option to say "for every GNUmakefile specified
in AC_CONFIG_FILES, generate a corresponding thin-wrapper Makefile"
would be a good move.  Patches in that direction will be very welcome,
once we have agreed about what such a thin wrapper should actually do
;-)

>>> In fact, is it possible to write a
>>> Makefile that compares the encoded settings of $(MAKE) set at configure
>>> time, against the current value of $(MAKE) from the current make
>>> implementation running the makefile, and which can re-execute and/or
>>> loudly abort if there is a mismatch?
>>>
>> Loudly aborting on such a mismatch would likely be possible I think, by
>> adding something like this to the footer.am:
>>
>>     all check clean distclean dist distcheck install uninstall: am--no-make-mismatch
>>     am--no-make-mismatch:
>>         @test '$(MAKE)' = '@MAKE@' || fatal mismatch
> 
> But will that always work?  If there are any uses of GNU-make specific
> syntax earlier in the file, will a less powerful make have already
> choked on that earlier syntax before getting to this point, negating the
> usefulness of the sanity check?
> 
Good point :-/  Albeit we wouldn't be using GNU-make specific syntax, we
might be using POSIX or "almost-portable" syntax the vendor make doesn't
grok.  Well, users on such inferior systems will just have to be more
careful I guess; they had to be so until today already, so they might be
used to it ...

> I speak from personal experience of using libvirt on a BSD machine;
> libvirt has already chosen to require GNU make.  So I used ./configure
> MAKE=gmake, then every so often I type 'make' instead of 'gmake' on that
> package, and get:
> 
> $ make
> Error expanding embedded variable.
>
> as my reminder to use gmake.  But I haven't taken time to track whether
> that error would happen from just automake code in a package that tried
> to be portable to all make, or whether it specific to the fact that
> libvirt's Makefile.am already used GNU-isms.
> 
>>
>> Well, almost: currently, if the make implementation in use (as specified
>> by ${MAKE-make}) doesn't set $(MAKE) automatically, configure code generated
>> by AM_INIT_AUTOMAKE causes $(MAKE) to be explicitly defined to '@MAKE@' in
>> the generated Makefile.in (to be later subst'ed by 'config.status' in the
>> resulting Makefile).  But this probably happens only with old broken make
>> implementations (and maybe configure could start simply punting when such
>> a borked make is detected?).
> 
> Is it worth a probe to see how many 'make's in the wild still fail to
> set $(MAKE)?
>
I think so, yes.  Albeit this is pretty low-priority (patches are always
welcome though).

>> In conclusion: if this approach can be made to work, a patch would be
>> very welcome, and could go directly into 1.13.2 (as the change would not
>> be invasive in the least, and would offer more reliable build systems).
> 
> Alas, I'm busy enough with other things (such as an overdue autoconf
> release) that it probably won't be me writing such a patch.
> 
Even more importantly, you have shown above that my approach cannot be
made to work ;-)

Regards,
  Stefano