Gavin Smith wrote:
On Wed, Mar 29, 2023 at 09:29:30PM -0500, Jacob Bachmeyer wrote:
Do we need a direct configure test for "has Perl module"?
AC_PERL_MODULE([Digest::SHA]) would need to execute `$PERL -e "require
Digest::SHA"` and consider Digest::SHA available if that returns success.
Using Perl's -M option works for most modules, but a few (such as
Devel::Cover) produce effects beyond the perl process when import is called,
so simply evaluating "require" is less likely to cause weirdness.
(Theoretically, a module could do something when loaded with require, but
those kinds of side effects are strongly discouraged. Devel::Cover creates
a coverage database in the current directory when import is called, but does
nothing when loaded with "require".)
It would likely be possible to implement whatever tests were desired.
For example, the Texinfo package has several occurences of checks for
Perl modules. Some of them occur at run-time, some at configure-time,
and some are fatal and some are non-fatal.
Here's an example of a configure check in configure.ac:
AC_MSG_CHECKING([Perl version for tests requiring unicode collation])
if $PERL -e "use 5.018_001; use Unicode::Collate" >/dev/null 2>&1; then
perl_unicode_collation_requirement='yes'
else
perl_unicode_collation_requirement='no'
fi
AC_MSG_RESULT($perl_unicode_collation_requirement)
PERL_UNICODE_COLLATE_OK=$perl_unicode_collation_requirement
AC_SUBST([PERL_UNICODE_COLLATE_OK])
This is a fair example of a case where a Perl version could be a
legitimate requirement, since Perl's Unicode support has often been
incomplete or buggy and is deeply intertwined into the Perl core.
However, while that is relevant for Texinfo, which must actually process
text in many alphabets (and in this case, I am guessing, perform proper
collation for building indexes), Automake and Autoconf deal primarily in
ASCII and secondarily in octet strings, such that the details of Unicode
support are irrelevant, and even the Perl 5.6 Unicode support is adequate.
This is also a fair start for an expansion for an AC_PERL_MODULE macro.
To continue with the example I used earlier:
AC_MSG_CHECKING([for Perl module Digest::SHA])
if $PERL -e 'require Digest::SHA' >/dev/null 2>&1; then
perl_module_Digest_SHA='yes'
else
perl_module_Digest_SHA='no'
fi
AC_MSG_RESULT($perl_module_Digest_SHA)
PERL_MODULE_DIGEST_SHA=$perl_module_Digest_SHA
AC_SUBST([PERL_MODULE_DIGEST_SHA])
The perl_* and PERL_* shell variable names can be obtained using the
patsubst ([::] -> [_]) and translit ([a-z] -> [A-Z]) GNU m4 builtins.
We probably should use the cache, so the expansion becomes: (I think)
AC_CACHE_CHECK([for Perl module Digest::SHA],
[ac_cv_perl_module_Digest_SHA],
[if $PERL -e 'require Digest::SHA' >/dev/null 2>&1; then
ac_cv_perl_module_Digest_SHA='yes'
else
ac_cv_perl_module_Digest_SHA='no'
fi])
PERL_MODULE_DIGEST_SHA=$ac_cv_perl_module_Digest_SHA
AC_SUBST([PERL_MODULE_DIGEST_SHA])
An example of a run-time check (for the Archive::Zip module, in the
EPUB output code):
eval { require Archive::Zip; };
my $archive_zip_loading_error = $@;
This discussion got started with a compile-time check (note that perl
compiles the program to an in-memory intermediate form immediately
before running it) that I wrote for Automake:
BEGIN { eval { require Time::HiRes; import Time::HiRes qw(stat) } }
This is a bit of an odd duck, because the semantics of importing
Time::HiRes::stat are to effectively replace the builtin stat operator
with an XSUB that returns timestamps with fractional seconds included.
As a consequence, while the result must be established before the rest
of the module is compiled, failing to import Time::HiRes::stat leaves an
obvious fallback: the original stat builtin that only gives integer
timestamps, which Automake now uses instead of failing if Time::HiRes is
not available.
Note that the run-time check you cite is (as I understand) subtly wrong
under most versions of perl, where edge cases exist that can allow an
exception to be caught, yet $@ remains undefined. I have never actually
seen this happen and I do not remember exactly what the supposed edge
cases are off the top of my head or if the edge cases were ever entirely
eliminated, but seem to recall that the only way to be certain is to set
a variable after the operation that can throw, like this:
my $archive_zip_loaded = 0;
eval { require Archive::Zip; $archive_zip_loaded = 1 };
my $archive_zip_loading_error = $@;
Later code then looks for more details in $archive_zip_loading_error iff
$archive_zip_loaded has remained false. The issues with $@ may have
been fixed at some point, but I typically use this "flag variable"
method as a defensive programming practice, since it works under all
versions of perl and is obviously correct upon inspection. This was not
an issue for importing Time::HiRes::stat in Automake, since the goal
there was simply to get the high-resolution timestamps if available.
-- Jacob