Subject: Re: [bug#61240] improve high-res file timestamp in Automake

From: Jacob Bachmeyer <[email-masked]>
Date: Sun, 05 Feb 2023 23:43:21 -0600

Paul Eggert wrote:
> On 2023-02-05 17:14, Jacob Bachmeyer wrote:
>
> [...]
>> Looking at the code, commit 01bf65daf6f6627b56fbe78fc436fd877ccd3537 
>> appears fine, all I am asking is that commit 
>> 4e3744a15c4d8bdb46c11ead2fb56c5f591b714b be reverted.  The current 
>> Automake Git master should actually work on Perl 5.6 if Time::HiRes 
>> has been installed, which was possible with 5.6 although it was 
>> bundled with Perl beginning with the 5.7.3 development release.
>
> Unfortunately the Perl version bump was prompted by evidence in the 
> field that without making it clear that bare Perl 5.6 does not 
> suffice, Autoconf and Automake fail in ways that are mysterious to 
> their users. We can't expect people to install extensions in Perl 5.6 
> to work around this problem. We must make things simple and easy for 
> installers and users to understand. Particularly since these are old 
> Perl versions that Autoconf and Automake users are unlikely to be 
> running (people who use bleeding-edge Autoconf and Automake almost 
> invariably run recent Perl).

I believe the proper autoconf solution would be for configure to verify 
that "$PERL -MTime::HiRes -e 1" completes successfully (that is, that 
$PERL has the Time::HiRes module available) and fail with a diagnostic 
that Time::HiRes is required if not, perhaps noting that Time::HiRes was 
bundled beginning with Perl 5.8.  (The 5.7 series were development 
releases.)

Note that the real requirement here is not a given Perl version, but the 
Time::HiRes module (solution to that below), so checking the Perl 
version is incorrect here.  Even though Perl 5.8 and later have 
Time::HiRes bundled, it is still a module and it is possible for a 
distribution package builder to separate Time::HiRes from the main perl 
package, so there is no guarantee that Time::HiRes will actually be 
available unless you explicitly test for it.  I doubt that any major 
distribution currently does this with Time::HiRes, but the Perl version 
does not actually imply the availability of any given module.

> It would be OK to go back to requiring only 5.6 if we can write 
> conditionalized code that works with 5.6 but with lower-res 
> timestamps, and quietly switches to higher-res timestamps if available 
> and works fine when they are available. Autoconf and Automake should 
> not rely on users installing optional Perl packages or dealing with 
> Perl's diagnostics when the optional stuff is missing: the code must 
> work out of the box with no expertise required.

I believe that is quite easy to do:

    BEGIN { eval { require Time::HiRes; Time::HiRes->import('stat') } }

instead of:

    use Time::HiRes qw(stat);

In Perl, "use Module LIST" is shorthand for "BEGIN { require Module; 
import Module LIST; }", so the above could also be written as "BEGIN { 
eval { require Time::HiRes; import Time::HiRes qw(stat) } }" if you 
wanted, although the direct package method call is a more common style.

If Time::HiRes is available, that will transparently replace stat() with 
Time::HiRes::stat(); if not, processing continues using the basic 
stat(), since require throws an exception immediately if it fails, which 
the eval BLOCK will catch.  This has the advantage of testing for the 
specific feature, and will give high-resolution timestamps even on 5.6 
if Time::HiRes is installed and basic timestamps otherwise.

Since Perl 5.8 and later all have Time::HiRes bundled, the import should 
succeed and high resolution timestamps will be available.  I say 
/should/ because it is possible for distribution packagers to separate 
bundled modules out from their main perl packages, as I mentioned above.

> Can you write an Automake patch to do that, and test it on old Perl 
> installations? 'git format-patch' form preferred. I don't have access 
> to ancient Perl and am a bit squeezed for time, so I'm afraid this 
> will need to be done by a Perl expert such as yourself.

The oldest Perl I normally use is a 5.8 installation from source that 
has (bundled) Time::HiRes, so I have perlbrew cooking up a 5.6.2 to test 
the fallback as I write this.

Should the patch be relative to commit 
6d6fc91c472fd84bd71a1b012fa9ab77bd94efea (before the version requirement 
bump) or should it include reverting commit 
4e3744a15c4d8bdb46c11ead2fb56c5f591b714b (the version requirement bump)?

-- Jacob